Linux命名管道:跨进程通信实战指南|附源码

上篇文章:进程池构建:高效任务派发与隐藏BUG揭秘全解析

目录

引言:为什么需要命名管道?

1.创建一个命名管道

1.1命令行创建

1.2代码中创建

2.匿名管道与命名管道的区别

3.命名管道的打开规则与同步机制

[4.C++ 实战:编写一个简单的 Server-Client 聊天程序](#4.C++ 实战:编写一个简单的 Server-Client 聊天程序)

代码:

总结


引言:为什么需要命名管道?

在学习进程间通信(IPC)时,我们通常首先接触的是匿名管道 (Anonymous Pipe) 。匿名管道简单好用,但它有一个致命的限制:只能在具有共同祖先(具有亲缘关系,如父子进程)的进程间通信。

那么,如果我们在系统中运行了两个完全不相关的进程,它们也想通过管道交换数据,该怎么办呢?这时候,命名管道(Named Pipe,也叫 FIFO)就闪亮登场了!

命名管道是一种特殊类型的文件,它在文件系统中有一个真实存在的路径名。因此,任何进程只要有权限访问该路径,就可以通过它进行通信。

1.创建一个命名管道

命名管道可以通过命令行创建,也可以在代码中动态创建。

1.1命令行创建

在终端中,我们可以使用 mkfifo 命令来创建一个命名管道:

复制代码
$mkfifo my_fifo$ ls -l my_fifo 
prw-rw-r-- 1 user user 0 Oct 24 10:00 my_fifo

注意观察 ls -l 的输出,文件类型是 p,代表 Pipe(管道文件)。

1.2代码中创建

在 C/C++ 程序中,我们使用 mkfifo 函数:

cpp 复制代码
#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *pathname, mode_t mode);
  • pathname: 管道文件的路径/名字。

  • mode : 文件的权限(例如 0666),实际权限会受系统的 umask 影响。

  • 返回值 : 成功返回 0,失败返回 -1 并设置 errno

创建命名管道:

cpp 复制代码
int main(int argc, char *argv[])
{
    mkfifo("p2", 0644);
    return 0;
}

2.匿名管道与命名管道的区别

很多初学者会疑惑,命名管道既然是个"文件",那通信时是不是把数据写到磁盘上了?速度会不会很慢?

答案是:绝对不会! 它们之间的区别仅仅在于"打开方式",底层通信介质其实是一样的。

对比维度 匿名管道 (Pipe) 命名管道 (FIFO)
创建方式 pipe() 函数 mkfifo 命令或函数
打开方式 创建时自动打开 使用 open() 函数像普通文件一样打开
适用范围 仅限有亲缘关系的进程 任意两个进程(只要能访问同一路径)
底层原理 内存级别的缓冲区,不写磁盘 文件系统中存在路径节点,但数据仍然只存在于内存缓冲区,不写磁盘

3.命名管道的打开规则与同步机制

命名管道自带同步机制,什么是同步?简单来说,就是"互相等待"。在使用open()函数时打开命名管道,有非常严格的阻塞规则:

  1. 如果你是为了"读"而打开 (O_RDONLY):

    • 阻塞模式(默认) :程序会卡在 open() 这里阻塞住,直到有另一个进程为了"写"打开了这个管道,程序才会继续往下走。

    • 非阻塞模式 (O_NONBLOCK):立刻返回成功。

  2. 如果你是为了"写"而打开 (O_WRONLY):

    • 阻塞模式(默认) :程序会卡在 open() 这里阻塞住,直到有另一个进程为了"读"打开了这个管道。

    • 非阻塞模式 (O_NONBLOCK) :立刻返回失败,错误码为 ENXIO(因为没人读,你写了也没意义)。

总结一句话:写端必须等读端,读端必须等写端。双方都准备好(都 open 成功)了,才能愉快地通信!

4.C++ 实战:编写一个简单的 Server-Client 聊天程序

接下来我们用代码实现一个单向通信:Client 发送消息,Server 接收并打印。

结果:

代码:

Makefile:

cpp 复制代码
all:client server
client:client.cc
	g++ -o $@ $^ -std=c++11
server:server.cc
	g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm -f client server

comm.h:

定义管道的名称,方便两边统一。

cpp 复制代码
#pragma once
#include <string>

const std::string fifoname = "fifo";

server.cc

服务器/读端,服务器负责创建管道、读取数据,并在结束后清理管道文件。

cpp 复制代码
#include <iostream>
#include <cstdio>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include "comm.h"

int main()
{
    // 1.创建管道文件
    umask(0);
    int n = mkfifo(fifoname.c_str(), 0666);
    if(n < 0)
    {
        perror("mkfifo");
        return 1;
    }

    // 2.打开管道文件
    std::cout << "open begin" << std::endl;
    int rfd = open(fifoname.c_str(), O_RDONLY);
    if(rfd < 0)
    {
        perror("open");
        return 2;
    }
    std::cout << "open end" << std::endl;

    char inbuffer[1024];
    // 3.进行通信
    while(true)
    {
        ssize_t n = read(rfd, inbuffer, sizeof(inbuffer)-1);
        if(n > 0)
        {
            inbuffer[n] = 0;
            std::cout << "client say# " << inbuffer << std::endl;
        }
        else if(n == 0)
        {
            // 写端关闭
            std::cout << "client quit, me too" << std::endl;
            break;
        }
        else
        {
            perror("read");
            break;
        }
    }

    // 关闭
    close(rfd);

    // 删除管道文件
    unlink(fifoname.c_str());

    return 0;
}

client.cc

客户端,直接打开以存在的管道文件,并发送终端输入的数据。

cpp 复制代码
#include <iostream>
#include <string>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "comm.h"

int main()
{
    std::cout << "open begin" << std::endl;
    int wfd = open(fifoname.c_str(), O_WRONLY);
    if(wfd < 0)
    {
        perror("open");
        return 1;
    }
    std::cout << "open end" << std::endl;

    std::string outstring;
    while(true)
    {
        std::cout << "Please Enter@ ";
        std::cin >> outstring;
        write(wfd, outstring.c_str(), outstring.size()); // 不需要写\0
    }
    close(wfd);

    return 0;
}

总结

通过这篇文章,我们了解到命名管道(FIFO)打破了匿名管道必须具有亲缘关系的限制 。虽然它以"文件"的形式存在于文件系统中,但其本质依然是内核中的一块内存缓冲区。掌握了命名管道的阻塞规则和使用方法,我们就掌握了 Linux 下最经典、最基础的进程间解耦通信方式之一。

如果你觉得这篇文章对你有帮助,欢迎点赞收藏!如有疑问,也欢迎在评论区留言讨论。

相关推荐
无心水1 小时前
【Harness:设计规范】15、Harness 成熟度模型(H0-H3):你的 AI 智能体在第几层
人工智能·设计规范·openclaw·养龙虾·harness·hermes·honcho
Raink老师7 小时前
【AI面试临阵磨枪-79】实时数据 RAG:订单、商家、物流、天气、动态库存
人工智能·面试·职场和发展
脑极体7 小时前
点亮星河AI+鸿蒙,一座艺术场馆的日神觉醒
人工智能·华为·harmonyos
Cosolar7 小时前
Chroma向量库面试学习指南
数据库·人工智能·面试·职场和发展·数据库架构
BUG指挥官7 小时前
Claude Code的自动化编程
人工智能
2301_809051147 小时前
Linux 网络编程 学习笔记
linux·网络·学习
wanhengidc7 小时前
服务器租用有何优点
运维·服务器·安全·web安全
笨蛋©7 小时前
2026年质量管理指南:泡泡图(Bubble Drawing)与自动化检验计划实战
ai·数字化·cad·质量管理·制造业
意图共鸣7 小时前
意图共鸣科技《认知智能白皮书》——感知与执行分离:认知架构(CA)如何重塑大模型底层结构
人工智能·架构
等一个人的@7 小时前
让数据自己开口:数睿通智库新增智能问数模块
人工智能·自然语言处理