Reading and writing data through a pipe
I have created two processes using fork(). The child process is producing and writing continuously a variable amount of data (array char) to the pipe. The parent process reads from the pipe and prints the received data to stdout.
The code is very simple:
switch (fork()) {
case -1:
exit (1);
break;
case 0:
close(fd[0]);
generate_data(fd[1]);
break;
default:
close(fd[1]);
while(1) {
n = read(fd[0], readbuffer, sizeof(readbuffer));
readbuffer[n] = 0;
if (n > 0)
printf ("read: %s\n", readbuffer);
else
exit(1);
}
break;
}
Where generate_data(int)
iterates over a list, writing each element (string) to the file descriptor given as argument (the write end of the pipe in this case):
void generate_data(int fd)
{
node_t node* = list;
while (node != NULL) {
write(fd, node->data, strlen(node->data)+1);
node = node->next();
}
}
The开发者_运维技巧 problem here is that the output is always unpredictable: the child process writes data to the pipe when the other process is processing the last read
, so when it calls to read again the rest of the data is not there anymore.
According to man 2 pipe
, this shouldn't be happening:
Data written to the write end of the pipe is buffered by the kernel until it is read from the read end of the pipe.
Taking a list of 10 elements, some output examples:
Example 1:
read: element_4
read: element_8
read: element_9
Example 2:
read: element_7
read: element_8
read: element_9
read: element_10
Example 3:
read: element_2
read: element_8
Anyone has any idea what's happening here?
You call read
and capture the return value, but then you largely ignore it; it's telling you how many valid bytes are in readbuffer
, but you're treating readbuffer
as if it contains a zero-terminated string, which it does not necessarily. In fact, a single read
may be giving you multiple zero-terminated strings, if your data-writing process is sending 0
bytes through the pipe; using printf
means you're ignoring the second and subsequent ones. At the very least, you'll need to use fwrite
to write the specific, correct number of bytes to stdout, although I suspect what you'll actually need to do is replace those zeroes with newlines first. It might be a better idea to modify generate_data
to send newlines instead of zeroes.
Read does not stop at the nul character, you might read two "messages" in one read() call. So your reader has to check if there is more data after the first 0 (but within the n bytes read), and save it. A next read call should append its data to this leftover. A special case is when there is a leftover, but not yet a complete message in the buffer.
精彩评论