【问题标题】:C pipe multiple message only one recievedC管道多条消息只收到一条
【发布时间】:2019-02-23 08:47:09
【问题描述】:

我正在尝试从父母向接收者发送两条消息。只收到一个。 Receiver 使用 stdin 和 stdout 作为管道,并将其结果输出到 std err。这是我的代码。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

int main(int argc,char * argv[])
{
    char buffer[100]; // The pipe's buffer
    int pipes[2];

    pid_t   childpid;

    if ( pipe(pipes) ){
        fprintf(stderr,"FATAL ERROR IN PIPE");
    }


    if((childpid = fork()) == -1){
            perror("fork");
            exit(1);
    }

    if(childpid == 0){
        close(pipes[1]);

        dup2(pipes[0],STDIN_FILENO);

        scanf("%s\n",buffer);
        fprintf(stderr,"REC: %s\n",buffer);
        scanf("%s\n",buffer);
        fprintf(stderr,"REC: %s\n",buffer);
        sleep(50);
    }
    else
    {
        close(pipes[0]);

        // Read in a string from the pipe 
        char* arr = "HelloWorld\n";
        write(pipes[1],arr,strlen(arr)+1);
        write(pipes[1],arr,strlen(arr)+1);  
        sleep(50);
    }
    return 0;   
}

【问题讨论】:

  • 管道中没有消息,只有字节流。
  • 没有消息是什么意思。我在父进程中发送了两次消息“HelloWorld\n”
  • 建议从scanf("%s\n",buffer); 的格式中删除"\n"。你认为"\n" 做了什么?可能是“只收到一个”的贡献者。
  • @Antoun 它的意思是“你似乎期望管道支持不同的消息,并且可以一次传递一个,但事实并非如此,管道只是字节”。至少这是我的解释。
  • 那程序怎么知道这是消息的结尾呢?

标签: c pipe ipc stdout stdin


【解决方案1】:

问题出在strlen(arr)+1 部分。您也在发送终止 nul 并且 nul 最终构成了 scanf 读取的第二个“字符串”:

REC: HelloWorld
REC: 

如果您删除+1,您将得到两条线(我还减少了睡眠时间,因为我没有足够的耐心等待 50 秒的结果):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>

int main(int argc,char * argv[])
{
    char buffer[100]; // The pipe's buffer
    int pipes[2];

    pid_t   childpid;

    if ( pipe(pipes) ){ fprintf(stderr,"FATAL ERROR IN PIPE"); }
    if((childpid = fork()) == -1){ perror("fork"); exit(1); }

    if(childpid == 0){
        close(pipes[1]);

        dup2(pipes[0],STDIN_FILENO);

        scanf("%s\n",buffer);
        fprintf(stderr,"REC: %s\n",buffer);
        scanf("%s\n",buffer);
        fprintf(stderr,"REC: %s\n",buffer);
        sleep(2);
    }
    else
    {
        close(pipes[0]);

        // Read in a string from the pipe 
        char* arr = "HelloWorld\n";
        write(pipes[1],arr,strlen(arr)); // << NO +1 
        write(pipes[1],arr,strlen(arr)); // << NO +1
        sleep(2);
    }
    return 0;   
}

【讨论】:

  • 几乎每个网站都提到应该有这个“+1”。 IE。 geeksforgeeks.org/c-program-demonstrate-fork-and-pipe
  • 当我删除它时还会发生未定义的行为。在我的大项目中,我同时使用许多管道。当我删除它并通过所有管道发送消息时。它并没有覆盖所有的孩子!
  • @Antoun 你那里有很多 UB(未检查的错误代码)。无论如何,如果您想将 nuls 保留在那里,为什么不跳过 stdio 并在整个过程中执行原始 IO 系统调用。 stdio 有问题。我不会用它。
  • 这是我必须使用 stdio 的作业
  • @Antoun +1 是因为他们故意发送终止 nul,用作分隔符。如果您愿意,您可以这样做,但这意味着您必须在接收端进行相应的解释。
【解决方案2】:

下面一行有一个问题:

scanf("%s\n",buffer);

scanf 不读取尾随空格(包括换行符),除非被指令匹配。但指令存在于此处。所以它会在输入之后的通常的新行之后等待另一个新行。

删除两个scanf 语句中的\n

其次,您必须修改您的fprintf 语句以在其中添加\n

fprintf(stderr,"REC: %s\n",buffer);

第三,不要给write中的strlen(arr)加1。修改为:

write(pipes[1],arr,strlen(arr));

它有效。见live demo

输出:

REC: HelloWorld
REC: HelloWorld

Real time: 2.082 s
User time: 0.043 s
Sys. time: 0.037 s
CPU share: 3.85 %
Exit code: 0

【讨论】:

  • 这是一个很好的假设,但实践并不同意(至少在我尝试过的平台上(glibc/linux、cygwin、macos))。
  • 我没有兼容的平台来试用它。所以我说“可能解决”。稍微修改了答案。
  • 经过多次更改后,它现在可以工作了。通过现场演示更新了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多