C - 子进程连续两次从管道读取,而不是读取一次然后阻塞

时间:2014-05-30 22:57:20

标签: c fork pipe

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

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

    1. 如果未创建子进程,则父进程会创建一个
    2. 孩子应该从匿名管道 1 消息中读取PER CLIENT。这意味着孩子应该从中读取。管道,打印msg,然后阻塞直到下一个客户端。
  4. 我现在遇到的问题是当只有一个连接的客户端时,有时孩子会阅读并打印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>
    

2 个答案:

答案 0 :(得分:0)

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

可能发生的事情是,在服务器while循环的第二次迭代中,open或read立即返回,返回值为-1(错误),因此循环再次执行。

调用read或open后,检查返回值,并检查errno是否返回-1。

你也会在循环的每次迭代中反复打开相同的fifo,而不会关闭它。

答案 1 :(得分:0)

我已经测试了以下解决方案,但它确实有效。

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

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

要处理这种情况,您可以执行以下两项操作之一。你可能应该同时做这两件事。

在服务器端检查读取呼叫的返回值

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

在客户端关闭管道,然后退出

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

任何一方本身都可以解决问题。但我建议同时做这两件事。