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]写入的内容,只会进入自己监听的读端,第三方程序根本没收到命令,自然不会返回响应。 - 需求完全可行,无需更换整体方案,只需调整管道结构:
- 创建两个管道:一个用于父进程向子进程发送命令(连接父进程写端与子进程
STDIN),另一个用于子进程向父进程返回输出(连接子进程STDOUT/STDERR与父进程读端) - 子进程启动时,将
STDIN重定向到命令管道的读端,STDOUT/STDERR重定向到输出管道的写端 - 父进程关闭无用的管道端,仅保留命令管道的写端(发命令)和输出管道的读端(收输出)
- 创建两个管道:一个用于父进程向子进程发送命令(连接父进程写端与子进程
修改后的核心代码示例:
// 创建两个管道: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
相关产品推荐
相关产品推荐

