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

Linux下C语言通过管道向外部程序发数据遇阻求助

问题描述

不熟悉Linux环境下的C语言开发,当前遇到技术瓶颈:
有一款第三方程序运行在Linux终端,可展示消息、接收键盘命令并返回响应。我编写了一个含两个线程的C程序,用pipe+fork实现:一个线程从管道接收数据,另一个超时后发送命令。核心代码如下:

if (pipe(pipefd) == -1) {
    perror("Error creating the pipe\n");
    return 1;
} else {
    pid_t pid = fork();
    if (pid == 0) {
        close(pipefd[0]);                                                               // Close reading descriptor
        dup2(pipefd[1], STDOUT_FILENO);                                                 // Redirect output flow to the pipe
        execl("../FolderApp", "App", "-n", "0", "-p", "/dev/ttyACM0", NULL);   // Execute the subprocess
        perror("Error executing the command\n");                                       // If we reach this line, there was a mistake executing the command
        exit(1);
    } else {
        pthread_create(&reading_th, NULL, promtReceiver, NULL);
        pthread_create(&sending_th, NULL, promtSender, NULL);
    }
}

接收功能正常,通过以下代码可获取第三方程序的所有输出:

bytes_read = read(pipefd[0],
        &internal_packet.buffer[internal_packet.buf_length],
        sizeof(internal_packet.buffer) - internal_packet.buf_length - 1);

但发送命令时出现问题:执行write(pipefd[1], "command\r\n", strlen("command\r\n"));后,仅能收到自己发送的命令内容,没有第三方程序的响应。第三方程序原本在命令合法时会回显命令并返回结果,非法时也会回显,但当前回显并非来自第三方程序。请问该需求是否可行?是否需要更换实现方案?


问题分析与解决
  • 核心问题:你只重定向了第三方程序的STDOUT到管道,但未将其STDIN与控制进程连通。当前你往pipefd[1]写入的内容,只会进入自己监听的读端,第三方程序根本没收到命令,自然不会返回响应。
  • 需求完全可行,无需更换整体方案,只需调整管道结构:
    1. 创建两个管道:一个用于父进程向子进程发送命令(连接父进程写端与子进程STDIN),另一个用于子进程向父进程返回输出(连接子进程STDOUT/STDERR与父进程读端)
    2. 子进程启动时,将STDIN重定向到命令管道的读端,STDOUT/STDERR重定向到输出管道的写端
    3. 父进程关闭无用的管道端,仅保留命令管道的写端(发命令)和输出管道的读端(收输出)

修改后的核心代码示例:

// 创建两个管道:cmd_pipe用于发命令,out_pipe用于收输出
int cmd_pipe[2], out_pipe[2];
if (pipe(cmd_pipe) == -1 || pipe(out_pipe) == -1) {
    perror("pipe create failed");
    return 1;
}

pid_t pid = fork();
if (pid == 0) {
    // 子进程:关闭无用的管道端
    close(cmd_pipe[1]);
    close(out_pipe[0]);

    // 重定向STDIN到命令管道的读端
    dup2(cmd_pipe[0], STDIN_FILENO);
    // 重定向STDOUT和STDERR到输出管道的写端
    dup2(out_pipe[1], STDOUT_FILENO);
    dup2(out_pipe[1], STDERR_FILENO);

    // 执行第三方程序
    execl("../FolderApp", "App", "-n", "0", "-p", "/dev/ttyACM0", NULL);
    perror("execl failed");
    exit(1);
} else {
    // 父进程:关闭无用的管道端
    close(cmd_pipe[0]);
    close(out_pipe[1]);

    // 保存管道描述符,供线程使用(注意线程安全)
    int global_cmd_write_fd = cmd_pipe[1];
    int global_out_read_fd = out_pipe[0];

    pthread_create(&reading_th, NULL, promtReceiver, NULL);
    pthread_create(&sending_th, NULL, promtSender, NULL);
}

对应调整线程代码:

  • 接收线程从输出管道读:
bytes_read = read(global_out_read_fd,
        &internal_packet.buffer[internal_packet.buf_length],
        sizeof(internal_packet.buffer) - internal_packet.buf_length - 1);
  • 发送线程向命令管道写:
write(global_cmd_write_fd, "command\r\n", strlen("command\r\n"));

补充说明:之前收到自己发送的内容,是因为你错误地往子进程的STDOUT管道写数据,然后又从同一个管道的读端读取,相当于自己发自己收,和第三方程序没有交互。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 01:45:24