gpt4 book ai didi

c - 使用未命名管道发送信息

转载 作者:太空宇宙 更新时间:2023-11-04 10:09:36 25 4
gpt4 key购买 nike

我的程序必须使用无名管道发送一些字节的信息。我有一个名为“input”的 txt 文件,它应该被程序读取,它的信息必须发送并写入另一个名为“output”的文件。我还必须使用 read()、write()、open() 函数。我的代码如下所示:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#define BUFSIZE 25

int main( int argc, char *argv[] ) {

srand(time(NULL));
pid_t pid;
int mypipefd[2];
int ret;
char buf[BUFSIZE];
int output;
int stream;
int nbytes;
ret = pipe(mypipefd);

if( ret == -1 ) {
perror( "pipe error");
exit(1);
}
pid = fork();

if( pid == -1 ) {
perror( "FORK ERROR...");
exit(2);
}
if( pid == 0 ) {
/* CHILD */
printf(" Child process...\n");
stream = open("input.txt", O_RDONLY);
if (close(mypipefd[0]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(3);
}
while ( (nbytes = read(stream, buf, BUFSIZE)) > 0 ) {
sleep(rand() %2);
write(mypipefd[1], buf, nbytes );
}
if ( close(stream) == -1 ) {
perror("ERROR CLOSING STREAM");
exit(4);
}
}
else {
/* PARENT */
printf(" Parent process...\n");
output = open("output.txt", O_CREAT | O_WRONLY, 00777);
while ( (nbytes = read(mypipefd[0], buf, BUFSIZE)) > 0 ) {
write(output, buf, nbytes);
}
printf("buf: %s\n", buf);
if (close(output) == -1) {
perror("ERROR CLOSING OUTPUT");
exit(5);
}
if (close(mypipefd[1]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(6);
}
}


return 0;

}

不幸的是代码不工作terminal screen

在我尝试 while 循环并一次发送所有信息之前,它起作用了,但输出文件看起来像这样 output file

输入文件看起来像这样input file

最佳答案

主要错误是父级必须在父级读取循环(和不在之后)。这可以防止在 child 写完后 parent 在管道上看到 EOF。

此外,您还缺少父级中的 waitpid

父级中 bufprintf 在错误的位置 [在读取循环之后]。在这一点上,不能保证 buf 有正确的数据或者它正确地以零终止。这就是为什么 stdout 最后有一些垃圾字符。

所以,除了输出到输出文件,循环应该输出到标准输出,但应该使用fwrite作为buf不能保证是零终止.

我在最初的帖子中遗漏了这一点,所以我已经更正了。

根据我的最高评论, child 应该循环 [可能] 部分写入管道。我编码了。

这是带有错误注释和修复的版本:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFSIZE 25

int main( int argc, char *argv[] ) {

srand(time(NULL));
pid_t pid;
int mypipefd[2];
int ret;
char buf[BUFSIZE];
int output;
int stream;
int nbytes;

ret = pipe(mypipefd);
if( ret == -1 ) {
perror( "pipe error");
exit(1);
}

pid = fork();
if( pid == -1 ) {
perror( "FORK ERROR...");
exit(2);
}

if( pid == 0 ) {
/* CHILD */
printf(" Child process...\n");
stream = open("input.txt", O_RDONLY);
if (close(mypipefd[0]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(3);
}

while ( (nbytes = read(stream, buf, BUFSIZE)) > 0 ) {
sleep(rand() %2);

#if 0
write(mypipefd[1], buf, nbytes );
#else
// NOTE: this _should_ work but adds extra at the end
int off;
int wlen;
for (off = 0; nbytes > 0; off += wlen, nbytes -= wlen) {
wlen = write(mypipefd[1], buf + off, nbytes );
if (wlen <= 0)
break;
}
#endif
}

if ( close(stream) == -1 ) {
perror("ERROR CLOSING STREAM");
exit(4);
}

// NOTE/FIX: child must close it's side of the pipe
#if 1
close(mypipefd[1]);
#endif
}

else {
/* PARENT */
printf(" Parent process...\n");

// NOTE/FIX: this must be closed _before_ the read loop -- holding it
// open prevents parent from seeing EOF on pipe
#if 1
if (close(mypipefd[1]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(6);
}
#endif

#if 1
printf("buf: ");
#endif

output = open("output.txt", O_CREAT | O_WRONLY, 00777);
while ( (nbytes = read(mypipefd[0], buf, BUFSIZE)) > 0 ) {
write(output, buf, nbytes);
#if 1
fwrite(buf,1,nbytes,stdout);
#endif
}

// NOTE/BUG: the buffer at this point will only have the data from
// the _last_ read and may not be null terminated
#if 0
printf("buf: %s\n", buf);
#else
printf("\n");
#endif

if (close(output) == -1) {
perror("ERROR CLOSING OUTPUT");
exit(5);
}

// NOTE/BUG: this must be closed _before_ the parent's read loop
#if 0
if (close(mypipefd[1]) == -1 ) {
perror("ERROR CLOSING PIPE");
exit(6);
}
#endif

// NOTE/FIX: this is missing (prevents orphan/zombie child process)
#if 1
waitpid(pid,NULL,0);
#endif
}

return 0;
}

更新:

but i don't understand what does "for" loop do here

对管道的写入可以生成“短写入”(例如,您想写入 20,但返回值(即 实际写入的字节数)返回 15。您必须索引放入缓冲区并在后续写入中写入剩余字节。

如果您执行了write(mypipefd[1],buf,10000000),那么在单个原子写入中可以写入多少字节存在内核限制(例如),内核不会为如此大的写入分配了空间,因此它将返回它可以附加到管道缓冲区的值 [在内核中]。

此外,假设内核管道缓冲区可以容纳 64 个字节。然后你向它写入大小为 64 的缓冲区。也许读者只读了 32 个字节。所以,第一次写没问题。然后读取器读出 32 个字节。所以,下一次写入64的管道,空间只有32字节,所以写入会返回32

Program have to display: "buf: This is ra" then "buf: ndom text"

好的,我已经解决了

At last, I need to implement error handling everywhere.

我已经注释了要添加错误和处理的地方,以及一些要查找的内容。

无论如何,这是一个更新版本。我保留了 //NOTE/* 注释,但删除了 #if/#endif 对以便于阅读。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#define BUFSIZE 25

int
main(int argc, char *argv[])
{

srand(time(NULL));
pid_t pid;
int mypipefd[2];
int ret;
char buf[BUFSIZE];
int output;
int stream;
int nbytes;

ret = pipe(mypipefd);
if (ret == -1) {
perror("pipe error");
exit(1);
}

pid = fork();
if (pid == -1) {
perror("FORK ERROR...");
exit(2);
}

if (pid == 0) {
/* CHILD */
printf(" Child process...\n");
stream = open("input.txt", O_RDONLY);
if (close(mypipefd[0]) == -1) {
perror("ERROR CLOSING PIPE");
exit(3);
}

while ((nbytes = read(stream, buf, BUFSIZE)) > 0) {
sleep(rand() % 2);

// NOTE/FIX: writing to pipes _can_ generate a _short_ write. that
// is, (e.g.) if the length given to write is 20, the return value
// may be only 15. this means that the remaining 5 bytes must be
// sent in a second/subsequent write
int off;
int wlen;
for (off = 0; nbytes > 0; off += wlen, nbytes -= wlen) {
wlen = write(mypipefd[1], buf + off, nbytes);
if (wlen < 0) {
perror("ERROR WRITING TO FILE");
exit(3);
}
if (wlen == 0)
break;
}
}

if (close(stream) == -1) {
perror("ERROR CLOSING STREAM");
exit(4);
}

// NOTE/FIX: child must close it's side of the pipe
// NOTE/ERRCODE: check error code here
close(mypipefd[1]);
}

else {
/* PARENT */
printf(" Parent process...\n");

// NOTE/FIX: this must be closed _before_ the read loop -- holding it
// open prevents parent from seeing EOF on pipe
if (close(mypipefd[1]) == -1) {
perror("ERROR CLOSING PIPE");
exit(6);
}

// NOTE/ERRCODE: this should be checked for -1 (i.e. output file
// could not be opened for file permission, etc. or other reasons
// similar to those for the file write below)
output = open("output.txt", O_CREAT | O_WRONLY, 00777);

// NOTE/FIX: we read one less than buffer size to allow for adding an
// artificial zero byte at the end
while ((nbytes = read(mypipefd[0], buf, BUFSIZE - 1)) > 0) {
// NOTE/ERRCODE: error handling _could_ be added here but it would
// be rare (e.g. filesystem has an I/O error because it's full or
// marked R/O because of an I/O error on the underlying disk)
write(output, buf, nbytes);

// write partial buffer to stdout
buf[nbytes] = 0;
printf("buf: %s\n",buf);
}

if (close(output) == -1) {
perror("ERROR CLOSING OUTPUT");
exit(5);
}

// NOTE/FIX: this is missing (prevents orphan/zombie child process)
// NOTE/ERRCODE: yes, this _can_ have an error return but here it's
// unlikely because we _know_ that pid is valid
// what can be done is to do:
// int status;
// waitpid(pid,&status,0)
// then process the return code from the child using the W* macros
// provided (e.g. WIFEXITED, WSTATUS) on status
waitpid(pid, NULL, 0);
}

return 0;
}

关于c - 使用未命名管道发送信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49907432/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com