为啥使用管道在 IPC 中使用 write() 而不是 print() 打印输出两次?

Posted

技术标签:

【中文标题】为啥使用管道在 IPC 中使用 write() 而不是 print() 打印输出两次?【英文标题】:Why is the output printed twice with write() and not with print() in IPC using pipe?为什么使用管道在 IPC 中使用 write() 而不是 print() 打印输出两次? 【发布时间】:2013-03-12 18:57:15 【问题描述】:

我的问题很简单直接。在这里我试图在管道的一端发送数据并尝试从另一端读取。我正在尝试学习 IPC 机制,但在执行这个简单的程序时遇到了困难.如果我在父进程中使用 print()[1] 那么,

o/p is 

In the child process
IN the parent process and its sleeping
SUBI IS IN LOVE WITH PUTHALATH

但是如果我在父进程中使用 write()[2 在下面的程序中注释]

 o/p is 

 In the child process
 IN the parent process and its sleeping
 SUBI IS IN LOVE WITH PUTHALATHIN the parent process and its sleeping

为什么会打印两次“IN the parent process and its sleep”行?

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>

int main()

   int fd[2];
   pipe(fd);

  if(!fork())
    printf("In the child process\n");
    close(1);
    dup(fd[1]);
    close(fd[0]);
    write(1,"SUBI IS IN LOVE WITH PUTHALATH", 200);

    else 
      sleep(1);
      printf("IN the parent process and its sleeping \n");
      char* stream;
      close(fd[1]);
       read(fd[0],stream,200);
       printf("%s",stream);------>(1)
      // write(1,stream,200);---->(2)
    
     return 0;
    

任何帮助请因为我被困在这里。

【问题讨论】:

注意:您没有将内存分配给stream。因此read 是未定义的行为。 stream 的名称令人困惑。称它为buf 并声明它为char buf[256]; 【参考方案1】:

在孩子身上,你

write(1,"SUBI IS IN LOVE WITH PUTHALATH", 200);

将 200 个字节写入管道,从字符串文字开始的位置开始。

当你

write(1,stream,200);

在父级中(在将内存分配给stream 之后),您将子级写入管道的200 个字节写入,而printf 在终止字符串文字"SUBI IS IN LOVE WITH PUTHALATH" 的0 字节处停止。

因此,内存中该字符串文字后面的任何字节也会被打印出来。字符串文字 "IN the parent process and its sleeping \n" 显然位于该内存部分中。

【讨论】:

> 感谢您的解释。 我不明白的一件事是在孩子中,我从字符串的开头开始写 200 个字节。但字符串的实际长度只有 30 个字节。那么剩下的写入字节呢管道。它会在剩下的 200-30 = 170 个字节中写入 null 吗? 您告诉它写入 200 个字节,并给它一个地址来查找字节(请记住,write 看到的所有“SUBI ...”都是第一个byte;write 不知道它是一个字符串,所以当它到达 0 终止符时它没有理由停止;它会一直持续到它写入指定的 200 个字节,或者由于访问冲突而停止 [如果你告诉它写超过缓冲区的大小,它很高兴超过])。在字符串文字的 31 个字节(包括 0 终止符)之后,它继续写入存储在它之后的任何内容。 > 好的,我明白了。因为我在父进程中像这样使用 write(1,stream,strlen(stream))-->(2),它只打印字符串“SUBI IS IN喜欢 PUTHALATH”。因为 strlen() 在第一个空字符处停止。这就是为什么在使用 write() 而不是 print() 在父进程中打印时,它只打印了这 30 个字节而不是整个 200 个字节。我是对的 Dani ? 是的,如果你使用strlen(stream)作为write的大小参数,你告诉它只写到第一个0字节。现在,如果子中的write只写入strlen("SUBI ....")字节,则需要将父reads的缓冲区初始化为0,否则你不知道第一个0字节在哪里,然后@ 987654334@ 可能导致未定义的行为并可能崩溃。【参考方案2】:

错误

   It is not advisable to mix calls to output functions from the stdio library
   with low-level calls to write(2) for the file descriptor associated with
   the same output stream; the results will be undefined and very probably not
   what you want.

http://man7.org/linux/man-pages/man3/puts.3.html

正如其他人指出的那样,您没有为流分配内存..

【讨论】:

【参考方案3】:

当我尝试编译时,gcc 说:

22:12: warning: ‘stream’ may be used uninitialized in this function
[-Wuninitialized]

这是一个主要的迹象!

char *stream 更改为 char stream[200]; 并按预期工作。但是如果你在最后调用write,你会写出远远超出字符串的内容,并且在它之后发生在内存中的任何内容,并且由于它没有初始化为0,它可能是随机的垃圾。你可以用这个来纠正它:

write(1, stream, strlen(stream)); //correct length, not all 200 bytes

实际上,您不应该在父级中写入 200 个字节,因为您是从尚未分配的内存中写入的。该数字应等于字符串的长度(\0 加一)。

【讨论】:

以上是关于为啥使用管道在 IPC 中使用 write() 而不是 print() 打印输出两次?的主要内容,如果未能解决你的问题,请参考以下文章

go语言快速入门 IPC之管道通信 8

IPC概述

为啥我应该使用 gRPC 而不是 IPC / Simple websocket?

使用管道进行 IPC

go语言快速入门 IPC之Socket 9

怎样进行IPC连接?