Linux下Named Pipe工作原理及代码运行异常求助
Linux命名管道(Named Pipe)工作原理及代码问题排查
一、Linux命名管道(Named Pipe)工作原理
- 命名管道是一种特殊文件,通过文件系统路径标识,能实现无亲缘关系进程间的通信
- 严格遵循**FIFO(先进先出)**规则,数据写入顺序和读取顺序完全一致
- 本质是内核中的一块缓冲区,磁盘上仅保留inode节点,不存储实际传输的数据
- 默认阻塞特性:
open()命名管道时,读端会阻塞到有写端打开,写端也会阻塞到有读端打开;可通过O_NONBLOCK标志取消阻塞 - 传输特性:基于字节流通信,支持两端同时以读写模式打开,也可分别以只读/只写模式打开
二、代码问题分析与修复
1. 核心错误点
发送端问题
- 运算符优先级错误:
if(fd = open("./hello", O_RDWR) < 0)中,<优先级高于=,导致fd被赋值为比较结果(0或1),而非实际文件描述符 - 错误提示文案不符:打开失败时提示"Failed to make fifo",实际是
open操作失败
接收端问题
- mkfifo参数错误:
mkfifo第二个参数是文件权限(如0666),不是打开模式(O_RDWR),会导致管道创建失败或权限异常 - 同样存在运算符优先级错误:
if(fd = mkfifo("./hello", O_RDWR) < 0)中fd被错误赋值 - 输出缓冲问题:
printf("Waiting for fifo update");无换行符,导致输出被缓冲,看起来像无输出 - 管道创建逻辑不合理:发送端先运行时会因管道不存在直接退出,接收端应负责管道创建
2. 修复后的完整代码
发送端(fifoSender.c)
#include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define MSG_SIZE 100 // SENDER int main() { char msg[MSG_SIZE] = "FIFO is for first-in, first-out."; int fd; // 修复优先级问题,修正错误提示 if( (fd = open("./hello", O_WRONLY)) < 0 ) { perror("Failed to open fifo for writing"); printf("Error code: %d\n", errno); exit(1); } int len = strlen(msg) + 1; // 包含字符串终止符 if(write(fd, msg, len) == -1) { perror("Failed to write into fifo"); exit(1); } else { printf("Succeed to write msg!\n"); } close(fd); // 关闭文件描述符 return 0; }
接收端(fifoReader.c)
#include <fcntl.h> #include <sys/stat.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #define MSG_SIZE 100 // READER int main() { char msg_rc[MSG_SIZE]; int fd; const char *fifo_path = "./hello"; // 检查管道是否存在,不存在则创建 if(access(fifo_path, F_OK) != 0) { // mkfifo第二个参数改为权限值,修复优先级问题 if( mkfifo(fifo_path, 0666) < 0 ) { perror("Failed to create fifo"); exit(1); } } // 以只读模式打开管道,修复优先级问题 if( (fd = open(fifo_path, O_RDONLY)) < 0 ) { perror("Failed to open fifo for reading"); exit(1); } printf("Waiting for fifo update...\n"); ssize_t read_len = read(fd, msg_rc, MSG_SIZE); if(read_len == -1) { perror("Failed to read from fifo"); exit(1); } else if(read_len == 0) { printf("Write end of fifo closed.\n"); } else { printf("Read msg : %s\n", msg_rc); } close(fd); unlink(fifo_path); // 使用完删除管道 return 0; }
3. 运行步骤
- 编译代码:
gcc fifoSender.c -o fifoSender gcc fifoReader.c -o fifoReader - 先启动接收端(会阻塞等待发送端连接):
./fifoReader - 在另一个终端启动发送端:
./fifoSender - 接收端会输出读取到的消息,发送端输出成功提示
内容的提问来源于stack exchange,提问作者happychild
相关产品推荐
相关产品推荐

