通过管道读写数据

发布于 2024-12-03 18:35:13 字数 1314 浏览 0 评论 0原文

我使用 fork() 创建了两个进程。子进程正在生成可变数量的数据(数组字符)并将其连续写入管道。父进程从管道读取数据并将接收到的数据打印到stdout。

代码非常简单:

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;
}   

generate_data(int) 迭代列表,将每个元素(字符串)写入作为参数给出的文件描述符(在本例中为管道的写入端):

void generate_data(int fd) 
{
   node_t node* = list;
   while (node != NULL) {
     write(fd, node->data, strlen(node->data)+1);
     node = node->next();
   }

}

其中 这里的问题是输出总是不可预测的:当另一个进程正在处理最后一个读取时,子进程将数据写入管道,因此当它再次调用读取时,其余数据不再存在。

根据 man 2 pipeline 的说法,这种情况不应该发生:

写入管道写入端的数据由 内核直到从管道的读取端读取它。

获取包含 10 个元素的列表,一些输出示例:

示例 1:

read: element_4
read: element_8
read: element_9

示例 2:

read: element_7
read: element_8
read: element_9
read: element_10

示例 3:

read: element_2
read: element_8

有人知道这里发生了什么吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

べ繥欢鉨o。 2024-12-10 18:35:13

您调用 read 并捕获返回值,但随后您基本上会忽略它;它告诉您 readbuffer 有多少有效字节,但您将 readbuffer 视为包含以零结尾的字符串,但事实并非如此。事实上,如果您的数据写入过程通过管道发送 0 字节,则单个读取可能会给您多个以零结尾的字符串;使用 printf 意味着您将忽略第二个和后续的。至少,您需要使用 fwrite 将特定的、正确的字节数写入标准输出,尽管我怀疑您实际上需要做的是首先用换行符替换这些零。修改generate_data以发送换行符而不是零可能是一个更好的主意。

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.

禾厶谷欠 2024-12-10 18:35:13

读取不会在 nul 字符处停止,您可能会在一次 read() 调用中读取两条“消息”。因此,您的读取器必须检查第一个 0 之后(但在读取的 n 个字节内)是否有更多数据,并保存它。下一次读取调用应将其数据附加到此剩余部分。一种特殊情况是缓冲区中有剩余但尚未完整的消息。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文