【问题标题】:C - Child process reads from pipe twice in a row instead of reading once and then blockingC - 子进程连续两次从管道读取,而不是读取一次然后阻塞
【发布时间】:2014-05-30 22:57:19
【问题描述】:

我需要用 C 语言构建两个程序:一个服务器和一个客户端,它们实现以下功能:

  1. 当我启动服务器时,他创建了一个命名管道 (O_RDONLY) 阻塞自己,直到客户端连接。
  2. 客户端使用通过 O_WRONLY 打开的命名管道向客户端发送一条消息,从而解锁服务器。
  3. 服务器接收到消息,然后将该消息传递给一个孩子(使用匿名管道),该孩子在屏幕上打印该消息。

    1. 如果未创建子进程,则父进程创建一个
    2. 孩子应该从匿名管道 1 消息中读取每个客户。这意味着孩子应该从匿名开始阅读。管道,打印消息,然后阻塞直到下一个客户端。

我现在遇到的问题是有时当只有 1 个连接的客户端时,孩子会阅读并打印 TWICE 消息

我已经在这里工作了 8 个小时,但我无法弄清楚。请有人帮我解决这个问题,我在这里发疯了。这是我到目前为止的代码:

客户

int main(int argc, char* argv[]){
int pPedido;
pPedido = open("pedido",O_WRONLY);
char buffer[6] = "ABCDE";
write(pPedido,buffer,6);
printf("FECHOU\n");
return 0;
}

服务器

int main(int argc, char* argv[]){
int exists = 0;
int pipeID[2];
int pPedido;
char buffer [100];
mkfifo("pedido",0666);

while(1){
    pPedido = open("pedido",O_RDONLY);
    read(pPedido,buffer,6);

    if(exists == 1){
        write(pipeID[1],"ABC",4);
    }
    else{
        pipe(pipeID);
        if(fork() == 0){
            char bufferzito[100];
            while(1){
                read(pipeID[0],bufferzito,4);
                printf("%s\n",bufferzito);
            }
        }
        else{
            write(pipeID[1],"ABC",4);
            exists = 1;
        }
    }
}
return 0;
}

这些是我使用的包含。我认为其中一些是不必要的。

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

【问题讨论】:

  • 请注意:我编辑了您的帖子以漂亮地格式化包含内容。为此,我将第一个从您发布的文字“stdio”修改为#include &lt;stdio.h&gt;。我在假设您的代码不会编译的情况下添加了.h,但如果您的代码中确实有#include &lt;stdio&gt;请回滚编辑!
  • 从管道读取时,read() 可能会在读取所有内容之前返回。与其将“ABC”从父进程发送到子进程,不如将您从管道中读取的内容发送到子进程。这样您就可以知道来自客户端的消息是否被拆分为 2 次读取。

标签: c fork pipe


【解决方案1】:

您没有检查来自openread 的返回值。这两个函数都可以返回 -1 来指示错误。

可能发生的情况是,在服务器 while 循环的第二次迭代中,打开或读取立即返回并返回值 -1(错误),因此您的循环再次执行。

调用read或open后,检查返回值,如果返回-1,还要检查errno。

您还在循环的每次迭代中一次又一次地打开同一个 fifo,而从未关闭它。

【讨论】:

    【解决方案2】:

    我已经测试了以下解决方案并且它有效。

    问题似乎是客户端在没有关闭管道的情况下退出。

    不知何故,这会导致第二次读取将 0 字节写入缓冲区。根据文档,将0 作为read 的返回值意味着EOF。我不确定为什么我们在客户端第一次连接时没有获得第二次读取。

    要处理这种情况,您可以做以下两件事之一。不过,您可能应该同时做这两个。

    在服务器端检查读取调用的返回值

    ...
    int n = read(pPedido,buffer,6);
    if(n==0) continue;
    ...
    

    在客户端退出前关闭管道

    ...
    printf("FECHOU\n");
    close (pPedido);
    return 0;
    

    任何一个都可以解决问题。但我建议两者都做。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多