我的程序必须使用未命名的管道发送一些字节的信息。 我有一个名为“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
答案 0 :(得分:1)
主要错误是父必须在父读取循环之前执行close(mypipefd[1])
(并且之后不)。在孩子完成写作后,这会阻止父母在管道上看到EOF。
此外,您错过了父母的waitpid
。
父级printf
的{{1}}位于错误的位置[读取循环之后]。此时,buf
无法保证拥有正确的数据,或者它已正确终止。这就是为什么stdout最后会有一些垃圾字符。
因此,除了输出到输出文件之外,循环应该输出到stdout,但是应该使用buf
,因为fwrite
不能保证零终止。
我在最初的帖子中错过了,所以我已经纠正了它。
根据我的最高评论,孩子应该循环[可能]部分写入管道。我把它编码了。
这里是带有注释和修复错误的版本:
buf
<强>更新强>
但我不明白&#34;对于&#34;循环做到这里
写入管道可以生成&#34;短写入&#34; (例如,您希望写入20但返回值(即实际写入的字节数)返回15.您必须索引到缓冲区并在后续写入中写入剩余的字节。
在单个原子写入中可以写入多少字节的内核限制(例如)如果你做#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;
}
,内核没有为这么大的写分配空间,所以它将返回它可以附加到管道缓冲区[在内核中]的值。
另外,让我们说内核管道缓冲区可以容纳64个字节。然后你写了大小为64的缓冲区。也许读者只读32个字节。所以,第一次写就好了。然后读者读出32个字节。因此,下一次写入64管道时,只有32字节的空间,因此写入将返回32
程序必须显示:&#34; buf:这是ra&#34;那么&#34; buf:ndom text&#34;
好的,我已经修好了
最后,我需要在任何地方实现错误处理。
我注释了我添加错误和处理的地方,以及一些要查找的内容。
无论如何,这是一个更新版本。我已经在write(mypipefd[1],buf,10000000)
条评论中删了,但删除了// NOTE/*
对以便于阅读。
#if/#endif