C进程与Python子进程双向通信问题(基于双FIFO实现)
排查C→Python方向FIFO通信失效的常见坑点
老哥,你这个C+Python跨进程双向通信加日志的场景,我之前也踩过不少坑,尤其是FIFO方向失效的问题,大概率是在FIFO打开时机、子进程重定向、或者阻塞行为这几个地方出了问题,咱们一个个捋:
1. FIFO的打开顺序绝对是重灾区
有名管道(FIFO)的核心特性是:必须一端先打开读,另一端才能成功打开写(反之亦然),否则会一直阻塞在open()调用上。比如你如果在C进程里先创建FIFO,然后直接打开写端,这时候Python子进程还没启动,C就会卡在open()那里,根本没法继续启动子进程,自然没法通信。
解决办法:
- 先创建两个FIFO,然后立刻
fork()子进程 - 子进程(Python端)先打开对应的读/写FIFO,再执行Python脚本
- 父进程(C端)fork后,等待子进程完成FIFO打开操作(可以加个短
sleep(1),生产环境用信号/文件锁更可靠),再打开自己的写/读FIFO
2. 子进程的stdin/stdout重定向别搞反
你要C往Python发数据,Python必须从C→P的FIFO读取对吧?那你在启动Python子进程时,有没有把它的stdin重定向到这个FIFO?如果没做重定向,Python默认读键盘输入,自然收不到C发的数据。
另外你要单独捕获Python的stdout做日志,这时候得用pipe管道来实现,不能和FIFO混在一起,否则会干扰双向通信的逻辑。
示例代码片段
C端核心逻辑
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/wait.h> #include <string.h> #define FIFO_C_TO_P "c_to_p.fifo" #define FIFO_P_TO_C "p_to_c.fifo" int main() { // 创建FIFO,设置全读写权限 if (mkfifo(FIFO_C_TO_P, 0666) == -1 || mkfifo(FIFO_P_TO_C, 0666) == -1) { perror("mkfifo failed"); exit(1); } // 创建pipe用于捕获Python的stdout int stdout_pipe[2]; if (pipe(stdout_pipe) == -1) { perror("pipe failed"); exit(1); } pid_t pid = fork(); if (pid == 0) { // 子进程:配置Python的输入输出 close(stdout_pipe[0]); // 关闭pipe读端 dup2(stdout_pipe[1], STDOUT_FILENO); // 重定向stdout到pipe写端 close(stdout_pipe[1]); // 重定向stdin到C→P的FIFO int c_to_p_fd = open(FIFO_C_TO_P, O_RDONLY); if (c_to_p_fd == -1) { perror("open c_to_p fifo failed"); exit(1); } dup2(c_to_p_fd, STDIN_FILENO); close(c_to_p_fd); // 启动Python脚本 execlp("python3", "python3", "py_script.py", NULL); perror("execlp failed"); exit(1); } else { // 父进程:处理日志读取和FIFO写操作 close(stdout_pipe[1]); // 关闭pipe写端 // 读取Python的stdout日志 char log_buf[256]; ssize_t n; printf("Capturing Python stdout:\n"); while ((n = read(stdout_pipe[0], log_buf, sizeof(log_buf)-1)) > 0) { log_buf[n] = '\0'; printf("[LOG] %s", log_buf); } close(stdout_pipe[0]); // 等待子进程打开FIFO后,写入测试数据 sleep(1); int c_to_p_fd = open(FIFO_C_TO_P, O_WRONLY); if (c_to_p_fd == -1) { perror("open c_to_p fifo failed"); exit(1); } const char* msg = "Hello from C process!"; write(c_to_p_fd, msg, strlen(msg)); close(c_to_p_fd); // 等待子进程退出,清理FIFO wait(NULL); unlink(FIFO_C_TO_P); unlink(FIFO_P_TO_C); } return 0; }
Python端脚本(py_script.py)
import sys # 读取C进程发来的数据(stdin已重定向到FIFO) data = sys.stdin.read() print(f"Python received: {data}") # 可选:往P→C的FIFO回发数据 # with open("p_to_c.fifo", "w") as f: # f.write("Hello from Python!")
3. FIFO的权限设置别偷懒
创建FIFO时一定要设置足够的权限,比如mkfifo("c_to_p.fifo", 0666),不然Python进程可能因为权限不足无法打开FIFO,直接静默退出,你还找不到原因。
4. Python的读取逻辑要匹配C的写入方式
如果Python用input()或sys.stdin.readline()读取,但C发送的数据没有换行符,Python会一直等待换行,看起来就像没收到数据。可以:
- C发送时末尾加换行符
- Python用
sys.stdin.read()读取(直到FIFO被关闭) - 双方约定固定长度的字节,Python循环读取指定长度
如果还是不行,可以把你的实际代码片段贴出来,我帮你再细查~
内容的提问来源于stack exchange,提问作者rcplusplus
相关产品推荐
相关产品推荐

