欢迎光临护送网
详情描述

Linux进程间通信:命名管道(FIFO)详解

一、什么是命名管道(FIFO)

命名管道是一种特殊的文件类型,允许无亲缘关系的进程之间进行通信。与匿名管道(pipe)不同,FIFO在文件系统中有一个真实的文件名,任何知道该文件名的进程都可以访问它。

二、FIFO的核心特性

持久性:在文件系统中可见,直到被显式删除 半双工:数据单向流动(需要两个FIFO实现双向通信) 阻塞I/O:默认读写操作会阻塞,直到另一端有操作 字节流:数据以字节流形式传输,无消息边界

三、创建与使用FIFO

创建FIFO的两种方式

1. 命令行创建

# 创建命名管道
mkfifo /tmp/myfifo

# 查看文件类型
ls -l /tmp/myfifo
# 输出:prw-r--r-- 1 user user 0 Jan 1 12:00 /tmp/myfifo
# 'p' 表示管道文件

2. 程序内创建

#include <sys/types.h>
#include <sys/stat.h>

// 创建FIFO,mode为权限(如0666)
int mkfifo(const char *pathname, mode_t mode);

四、完整示例:生产者-消费者模型

生产者程序(writer.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define FIFO_FILE "/tmp/myfifo"
#define BUFFER_SIZE 1024

int main() {
    int fd;
    char buff[BUFFER_SIZE];

    // 创建FIFO(如果不存在)
    if (mkfifo(FIFO_FILE, 0666) == -1) {
        // 可能已存在,继续尝试打开
    }

    printf("生产者启动,等待消费者连接...\n");

    // 打开FIFO进行写入(会阻塞直到消费者打开读取端)
    fd = open(FIFO_FILE, O_WRONLY);

    while (1) {
        printf("输入消息 (输入'quit'退出): ");
        fgets(buff, BUFFER_SIZE, stdin);

        // 写入FIFO
        write(fd, buff, strlen(buff)+1);

        if (strncmp(buff, "quit", 4) == 0) {
            break;
        }
    }

    close(fd);
    // unlink(FIFO_FILE); // 可选:删除FIFO文件
    return 0;
}
消费者程序(reader.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#define FIFO_FILE "/tmp/myfifo"
#define BUFFER_SIZE 1024

int main() {
    int fd;
    char buff[BUFFER_SIZE];

    printf("消费者启动,等待数据...\n");

    // 打开FIFO进行读取(会阻塞直到生产者打开写入端)
    fd = open(FIFO_FILE, O_RDONLY);

    while (1) {
        // 从FIFO读取数据
        int bytes_read = read(fd, buff, BUFFER_SIZE);

        if (bytes_read > 0) {
            printf("收到消息: %s", buff);

            if (strncmp(buff, "quit", 4) == 0) {
                break;
            }
        }
    }

    close(fd);
    return 0;
}

五、编译与测试

# 编译
gcc writer.c -o writer
gcc reader.c -o reader

# 终端1:运行消费者
./reader

# 终端2:运行生产者
./writer

六、高级用法与技巧

1. 非阻塞模式
// 非阻塞方式打开FIFO
int fd = open(FIFO_FILE, O_RDONLY | O_NONBLOCK);

// 或通过fcntl设置
int flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
2. 多客户端服务器模型
// 服务器处理多个客户端
#include <errno.h>

void server_handle_multiple_clients() {
    int fd, bytes;
    char buffer[256];

    mkfifo("/tmp/server_fifo", 0666);

    while (1) {
        // 打开服务器FIFO(阻塞等待客户端)
        fd = open("/tmp/server_fifo", O_RDONLY);

        // 读取客户端请求
        while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) {
            printf("收到请求: %s\n", buffer);

            // 创建唯一的响应FIFO名
            char response_fifo[50];
            sprintf(response_fifo, "/tmp/client_%s_fifo", buffer);

            // 打开客户端FIFO并发送响应
            int resp_fd = open(response_fifo, O_WRONLY);
            write(resp_fd, "响应数据", 10);
            close(resp_fd);
        }

        close(fd);
    }
}
3. 双向通信实现
// 进程A创建两个FIFO
mkfifo("/tmp/AtoB", 0666);
mkfifo("/tmp/BtoA", 0666);

// 进程A:向AtoB写,从BtoA读
// 进程B:向BtoA写,从AtoB读

七、FIFO的限制与注意事项

容量限制:Linux默认64KB(可配置)

原子性:写入数据量≤PIPE_BUF(通常4096字节)时保证原子性

阻塞问题

  • 读空FIFO会阻塞,直到有数据写入
  • 写满FIFO会阻塞,直到有数据被读取
  • 所有写入端关闭后,读取返回0
  • 所有读取端关闭后,写入会触发SIGPIPE信号

清理问题:FIFO文件需要手动删除

// 删除FIFO文件
unlink("/tmp/myfifo");

八、与其他IPC方式的对比

特性 命名管道 匿名管道 消息队列 共享内存
无亲缘关系
文件系统可见
通信方向 半双工 半双工 全双工 全双工
性能
数据格式 字节流 字节流 消息 字节流

九、实际应用场景

Shell命令协同

# 终端1:创建并写入FIFO
mkfifo /tmp/myfifo
echo "Hello World" > /tmp/myfifo
终端2:从FIFO读取

cat < /tmp/myfifo


2. **日志收集系统**
```c
// 多个进程向同一个FIFO写入日志
// 日志收集进程从FIFO读取并统一处理
进程池任务分发
// 主进程向FIFO写入任务
// 工作进程从FIFO读取并执行

十、最佳实践

错误处理:始终检查系统调用返回值 信号处理:处理SIGPIPE等可能信号 资源清理:程序退出前删除FIFO文件 权限控制:设置适当的文件权限(如0600) 超时机制:使用select/poll防止永久阻塞
// 使用poll实现超时读取
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;

int ret = poll(fds, 1, 3000); // 3秒超时
if (ret > 0 && (fds[0].revents & POLLIN)) {
    read(fd, buffer, size);
}

命名管道作为一种简单有效的进程间通信机制,特别适用于单向数据流无亲缘关系进程的通信场景。虽然功能相对简单,但在许多系统编程场景中仍然非常实用。

相关帖子
用人单位对于“三期”女职工的工作量安排,应当遵循怎样的合理性原则?
用人单位对于“三期”女职工的工作量安排,应当遵循怎样的合理性原则?
舟山市营销网站建设@独立网站制作,价格透明
舟山市营销网站建设@独立网站制作,价格透明
电梯轿厢内的紧急报警按钮真的有用吗?按下后如何确认救援已收到?
电梯轿厢内的紧急报警按钮真的有用吗?按下后如何确认救援已收到?
哪些特殊类型的房屋在办理租赁备案时可能会遇到额外的限制?
哪些特殊类型的房屋在办理租赁备案时可能会遇到额外的限制?
如今手机不离手,打喷嚏时用手肘遮挡如何避免让你的手机成为污染源?
如今手机不离手,打喷嚏时用手肘遮挡如何避免让你的手机成为污染源?
“僵尸自行车”不仅影响美观,还可能带来安全隐患,我们该如何看待?
“僵尸自行车”不仅影响美观,还可能带来安全隐患,我们该如何看待?
2026年老年公交卡政策还在继续执行吗,各地关于老年人免费乘车的规则有哪些新变化?
2026年老年公交卡政策还在继续执行吗,各地关于老年人免费乘车的规则有哪些新变化?
2026年,企业更看重继续教育带来的软技能提升还是硬技能认证?
2026年,企业更看重继续教育带来的软技能提升还是硬技能认证?
黄金贷款合同签订技巧,读懂条款知识明确借贷双方权利义务
黄金贷款合同签订技巧,读懂条款知识明确借贷双方权利义务
安顺市长途救护车出租转运病人-24小时随叫随到
安顺市长途救护车出租转运病人-24小时随叫随到
台州市精准获客助手@网站制作设计服务,多年专业建站经验
台州市精准获客助手@网站制作设计服务,多年专业建站经验
物业公司提出的维修基金使用方案,业主们应该重点审核哪些内容?
物业公司提出的维修基金使用方案,业主们应该重点审核哪些内容?
珠海市电商网站建设#商城网站开发,企业解决方案
珠海市电商网站建设#商城网站开发,企业解决方案
齐齐哈尔市120救护车跨省护送病人回家-长途跨省救护车转运24小时电话
齐齐哈尔市120救护车跨省护送病人回家-长途跨省救护车转运24小时电话
母婴室从“有没有”到“好不好用”的转变,反映了怎样的社会观念进步?
母婴室从“有没有”到“好不好用”的转变,反映了怎样的社会观念进步?
关于单用途商业预付卡的管理办法,在2026年是否有重要的调整和变化?
关于单用途商业预付卡的管理办法,在2026年是否有重要的调整和变化?
开封市苹果手机app开发#模版网站开发设计,一站式建站服务
开封市苹果手机app开发#模版网站开发设计,一站式建站服务
除了卫生巾和棉条,2026年还有哪些创新产品在改变月经护理方式?
除了卫生巾和棉条,2026年还有哪些创新产品在改变月经护理方式?
房抵贷的房产评估价怎么定?和市场价差多少你心里要有数
房抵贷的房产评估价怎么定?和市场价差多少你心里要有数