You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

双向管道通信读取端出现Bad file descriptor错误排查

客户端-服务器双向管道通信问题解决

错误根源分析

  1. 管道写端未及时关闭导致read阻塞:父进程(服务器)在读取p2管道前,未关闭自身持有的p2[1](写端)。子进程写完关闭p2[1]后,管道写端仍有父进程的一个打开实例,read(p2[0], ...)会一直等待数据,陷入死循环。
  2. 进程等待时机错误:父进程先调用wait(NULL)等待子进程退出,再读取管道数据,可能导致管道资源提前回收,同时未关闭的写端依然会引发阻塞。
  3. 错误提示信息混淆:子进程写管道失败时,错误提示写成了"Can't read from the pipe!",与实际操作不符。

修复后的代码调整

父进程(服务器)代码调整

if (pid != 0)                           // server
{
    read(fd_client_to_server, word1, sizeof(word1));    // 读取客户端发送的命令
    printf(" I received this command...%s\n", word1);

    if (strcmp(word1, "read login : username") == 0 || strcmp(word1, "quit") == 0 || strcmp(word1, "logout") == 0 || strcmp("get-logged-users", word1) == 0 || strcmp("get-proc-info", word1) == 0) 
    {
        // 父进程仅向p1写数据,关闭p1读端
        close(p1[0]);
        if (write(p1[1], word1, sizeof(word1)) == -1)   
            perror("Can't write in the pipe\n");
        printf(" 2 I received this command...%s\n", word1);
        close(p1[1]);

        // 父进程仅从p2读数据,提前关闭p2写端,避免read阻塞
        close(p2[1]);
        // 先读取子进程返回的数据,再等待子进程退出
        if (read(p2[0], word2, sizeof(word2)) == -1)
            perror("Can't read from pipe\n");
        printf("4 I received this command...%s\n", word2);
        close(p2[0]);

        wait(NULL);                     // 等待子进程退出

        write(fd_server_to_client, word2, sizeof(word2)); // 将数据转发给客户端
    }
    else {
        printf("%s\n", "The server can't do this yet!");
    }
}

子进程(CP)代码调整

else {                                  // CP
    close(p1[1]);
    if (read(p1[0], word3, sizeof(word3)) == -1)    
    {
        perror("Can't read from the pipe!");
    }
    printf(" 2 I received this command...%s\n", word3);
    close(p1[0]);

    if (strcmp(word3, "quit") == 0)
        strcpy(word4, "yay!");

    close(p2[0]);
    if (write(p2[1], word4, sizeof(word4)) == -1) {
        perror("Can't write to the pipe!"); // 修正错误提示信息
    }
    printf(" 3 I received this command...%s\n", word4);
    close(p2[1]);
}

额外注意事项

  • 管道必须在fork()前调用pipe(p1)和pipe(p2)创建,确保父子进程继承正确的文件描述符。
  • 所有管道的未使用端需及时关闭,避免资源泄漏和不必要的阻塞。
  • 注意客户端发送命令可能携带的换行符,可使用strncmp或提前去除换行后再做字符串比较,避免匹配失败。

内容的提问来源于stack exchange,提问作者andreea_0607

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 20:05:25