
🔥小叶-duck:个人主页
❄️个人专栏:《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
✨未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游
目录
[一. 命名管道核心概念:什么是 FIFO?](#一. 命名管道核心概念:什么是 FIFO?)
[1.1 命名管道的定义](#1.1 命名管道的定义)
[1.2 命名管道的核心特性](#1.2 命名管道的核心特性)
[1.3 命名管道和匿名管道的区别与联系](#1.3 命名管道和匿名管道的区别与联系)
[二. 命名管道的创建方式](#二. 命名管道的创建方式)
[2.1 命令行创建(mkfifo 指令)](#2.1 命令行创建(mkfifo 指令))
[2.2 代码创建(mkfifo 函数)](#2.2 代码创建(mkfifo 函数))
[三. 命名管道的打开规则(重点)](#三. 命名管道的打开规则(重点))
[四. 命名管道实战案例](#四. 命名管道实战案例)
[4.1 案例 1:命名管道实现 Server-Client 通信](#4.1 案例 1:命名管道实现 Server-Client 通信)
[4.1.1 版本一](#4.1.1 版本一)
[4.1.2 版本二(优化)](#4.1.2 版本二(优化))
[4.2 案例 2:命名管道实现文件拷贝](#4.2 案例 2:命名管道实现文件拷贝)
[五. 命名管道使用总结](#五. 命名管道使用总结)
前言:
在 Linux 各类 IPC 通信方案里,匿名管道虽能完成父子、兄弟这类同源进程的数据交互,却受血缘绑定约束,无法用于独立无关进程通信。命名管道 FIFO 作为其衍生拓展,依托文件系统生成实体管道文件,凭借唯一文件名作为通信入口,摆脱了亲缘进程的使用局限,让任意进程都能依托文件路径完成数据收发。本文围绕 FIFO 的定义、创建接口、底层通信逻辑搭配实操代码,完整梳理非亲缘进程借助命名管道实现 IPC 的整套逻辑。
上篇补充(进程池的实现)
在上篇文章的最后我们利用匿名管道实现了一个简单的进程池,虽然执行过程没有任何问题,但是在代码上其实有一个比较隐蔽的问题:

也就是退出进程池的时候,我们之前的做法是先将全部管道的写端全部关闭之后,再等待全部子进程。
学习了前面知识的应该就会发现一个问题:最开始的管道先关闭就会导致对应的子进程Work函数结束返回,进而导致子进程结束,但是我们没有立即对其进行等待(因为还要关闭后续管道),使其变成僵尸进程,这其实是不应该的。
所以我们需要对这里进行优化。
那这里就会有人说了,我们直接关闭一个管道就等待,再关闭一个管道再等待不就行了,那我们就按照这种想法修改一下:



我们发现进程卡住了,这是什么情况呢?为什么我们修改成关闭管道就执行等待,就变成了这种情况?下面的图进行了解释:

那我们怎么解决这个问题呢?这里提供了两种方法:
解决方法一:逆序关闭管道
其实通过上面的图我们就会发现一个特点:就是越早创建的管道被指向的次数越多,而越晚创建的管道被指向的次数越少(因为越后面的子进程所拷贝的写端越多),而最后一个管道只有父进程一个写端指向,那么我们反向往上进行关闭本就行了吗?
因为我们关闭了最后一个管道的写端则管道就关闭了,则对应的子进程就会退出,那么上一个管道原本是被父进程和这个子进程同时指向,此时就只有父进程了,再进行关闭写端则管道也就关闭了,以此类推。


解决方法二:让子进程指向管道的写端提前关闭(只让父进程指向管道写端)
我们会发现上面的解决方法的确解决了阻塞问题,但是我们会发现其实底层进程的指向依旧没变,依旧是最早创建的管道被多次指向,这其实不符合进程池的要求,我们是希望一个管道就只有父进程和对应的子进程进行连通,而没有其他进程的干预,所以我们需要解决这个问题。
那怎么解决呢?其实我们会发现:我们对管道写端的关闭,无非就是让其引用计数减到0,而而我们就是需要想办法在不断创建子进程的过程中,所有管道的写端的引用计数始终为1,也就是只让父进程指向,那怎么做呢?
父进程for循环关闭自己的对应管道的写端,是让所有管道写端的引用计数减1,那子进程也for循环关闭管道的写端,不也能让管道写端的引用计数减1吗?所以我们的解决方法就是在子进程中for循环关闭管道的写端(使其引用计数减1,保证所有的管道写端引用计数始终为1)


这样我们所有的管道的写端也就只有父进程指向了,那么我们也就可以顺序关闭管道了。


到此,我们也就成功解决了这个问题了。
一. 命名管道核心概念:什么是 FIFO?
1.1 命名管道的定义
命名管道 (Named Pipe),又称 FIFO (First In First Out),是一种特殊的文件系统对 象(类型为 p),其核心本质与匿名管道一致 ------ 内核中的一块缓冲区 ,但通过文件路径作为标识,让任意进程都能通过该路径访问管道,实现跨进程通信。
与匿名管道相比,命名管道的核心差异的是 "命名":
- 匿名管道:无文件路径,仅通过 pipe() 创建的文件描述符在亲缘进程间共享;
- 命名管道:有明确的文件路径(如/tmp/myfifo),任意进程可通过open()打开该路径,实现通信。
1.2 命名管道的核心特性
- 跨进程通信:支持无亲缘关系的进程(如两个独立的应用程序)通信,突破匿名管道的亲缘限制;
- 半双工通信:数据单向流动,如需双向通信需创建两个命名管道;
- 基于文件操作 :遵循 Linux "一切皆文件" 思想,通过 open()/read()/write()/close() 等标准文件接口操作;
- 生命周期随内核 :命名管道创建后,即使创建进程退出,管道文件仍存在于文件系统中,需手动删除(unlink()或rm命令);
- 同步与互斥 :内核自动保证管道操作的同步(如读阻塞、写阻塞 )和互斥(同一时间仅允许一个进程写)。

1.3 命名管道和匿名管道的区别与联系
- 匿名管道 由 pipe函数创建并打开。
- 命名管道 由 mkfifo 函数创建,打开用 open
- FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,⼀但这些工作完成之后,它们具有相同的语义。
- 为了更清晰地理解命名管道的定位,整理两者的核心差异更详细的对比如下表所示
| 特性 | 匿名管道 | 命名管道 (FIFO) |
|---|---|---|
| 定义 | 一种半双工通信通道,通常用于具有亲缘关系的进程之间(如父子进程)。 | 一种特殊的文件(存在于文件系统中),允许无亲缘关系的进程间通信。 |
| 创建方式 | 通过 pipe() 系统调用创建,返回两个文件描述符(读端和写端)。 |
通过 mkfifo() 或 mknod() 创建,在文件系统中具有路径名。 |
| 标识 | 无名,仅通过文件描述符引用。 | 有名,通过文件系统中的路径名标识。 |
| 进程关系 | 仅适用于有共同祖先(如父子进程)的进程。 | 适用于任意进程,无论是否有亲缘关系。 |
| 通信方向 | 单向(半双工),数据只能从一个方向流动。 | 通常也是单向(半双工),但可通过打开两个管道实现双向通信。 |
| 持久性 | 随进程存在而存在,所有相关进程关闭管道后自动销毁。 | 随文件系统存在,可显式删除(unlink),即使没有进程打开也不会消失。 |
| 打开方式 | 无需显式打开,创建时直接获得文件描述符。 | 必须像普通文件一样用 open() 打开,使用路径名。 |
| 数据模型 | 字节流,无消息边界。 | 字节流,无消息边界。 |
| 阻塞行为 | 默认阻塞:读空管道或写满管道会使进程阻塞(可设置非阻塞)。 | 默认阻塞:读空 FIFO 或写满 FIFO 会使进程阻塞(可设置非阻塞)。 |
| 典型应用场景 | 父子进程间的简单通信,如命令管道 | 在 shell 中的使用 |
| 系统限制 | 容量通常有限(如 64KB),取决于系统实现。 | 容量通常有限,类似匿名管道,但受文件系统影响。 |
| 对比维度 | 匿名管道(pipe) | 命名管道(FIFO) |
|---|---|---|
| 通信范围 | 仅亲缘进程(父子、兄弟) | 任意进程(无亲缘关系) |
| 创建方式 | pipe()系统调用 |
mkfifo()函数或 mkfifo 命令 |
| 标识方式 | 文件描述符(fd 0、fd 1) | 文件系统路径(如./myfifo) |
| 生命周期 | 随进程(所有进程关闭描述符后释放) | 随内核(需手动unlink()删除) |
| 打开方式 | 无需open(),创建即打开 |
需通过open()打开路径 |
| 核心用途 | 亲缘进程间简单通信 | 无关联进程间通信(如 C/S 模型) |
联系:
- 通信机制 :两者都是操作系统提供的进程间通信(IPC)方式,基于内核缓冲区实现数据传输。
- 数据特性:都提供可靠的字节流服务,数据写入和读取的顺序一致,无消息边界。
- 行为相似 :默认情况下,读写操作具有相似的阻塞语义(读空阻塞、写满阻塞),并支持非阻塞标志。
- 单向性:本质上都是单向通信管道(半双工),若要双向通信需创建两个管道。
- 原子性 :在 PIPE_BUF限制内,写入操作具有原子性(多个进程同时写时数据不会交错)。
二. 命名管道的创建方式
命名管道有两种创建方式:命令行创建 和代码创建 ,本质都是在文件系统 中生成一个FIFO 类型的文件。
2.1 命令行创建(mkfifo 指令)
直接通过 mkfifo 指令 创建命名管道,语法简单,适合快速测试:
bash
# 创建名为myfifo的命名管道
mkfifo myfifo
# 查看管道文件(类型标识为p)
ls -l myfifo

我们可以发现,这里创建的管道文件(最前面的标识是p开头),就算我们是不停的在往里面进行写操作,但是它的文件大小是一直不变的,验证了我们上面图中所说的它不是一个普通文件。另外当我们直接终止读端的时候,这个时候的情况就相当于读端关闭,写端还在一起写,所以操作系统直接杀死了我们的进程。
2.2 代码创建(mkfifo 函数)
通过mkfifo() 系统调用 在代码中创建命名管道,需指定管道路径和权限,原型如下:
cpp
#include <sys/stat.h>
#include <sys/types.h>
// 参数:pathname-管道路径;mode-权限(如0644)
int mkfifo(const char *pathname, mode_t mode);
代码示例(创建命名管道):
cpp
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#define FIFO_PATH "./myfifo" //路径
int main()
{
// 创建命名管道,权限0644(所有者读+写,其他读)
int ret = mkfifo(FIFO_PATH, 0644);
if (ret == -1)
{
// 若管道已存在,errno为EEXIST,可忽略该错误
if (errno != EEXIST)
{
perror("mkfifo error");
return 1;
}
printf("命名管道已存在\n");
}
else
{
printf("命名管道创建成功\n");
}
return 0;
}
三. 命名管道的打开规则(重点)
命名管道的打开(open())行为与普通文件不同,普通文读端或者写端随时都可以打开文件 ;而命名管道的核心是**"读端与写端的同步"** ------仅当管道的读端和写端同时被打开后,通信才能正常进行,具体规则如下:
| 打开方式 | 行为描述 |
|---|---|
| 读方式打开(O_RDONLY) | - 若管道无写端打开:阻塞,直到有进程以写方式打开该管道;- 若指定 O_NONBLOCK:不阻塞,直接返回成功 |
| 写方式打开(O_WRONLY) | - 若管道无读端打开:阻塞,直到有进程以读方式打开该管道;- 若指定 O_NONBLOCK:不阻塞,返回失败(errno=ENXIO) |
| 读写方式打开(O_RDWR) | 不阻塞,直接打开(同时具备读和写权限,可实现单向通信的 "自我循环") |
注意 :实际开发中,建议读端以O_RDONLY 打开,写端以O_WRONLY打开,避免使用O_RDWR(可能导致通信逻辑混乱)。
四. 命名管道实战案例
4.1 案例 1:命名管道实现 Server-Client 通信
实现一个简单的 C/S 模型:
前置准备(Makefile)
- makefile
bash
.PHONY:all
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
4.1.1 版本一
服务端程序(server.cc):
cpp
#include <iostream>
#include "comm.hpp"
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
// server负责创建命名管道和读取数据
int main()
{
umask(0); // 默认umask为0002,修改umask为0,保证权限设置一一对应
// 1、创建命名管道fifo
// int mkfifo(const char *pathname, mode_t mode);
int n = mkfifo(FIFO_FILE, 0666); // 第二个参数就是传权限位mode
if (n < 0)
{
std::cerr << "mkfifo error" << std::endl;
return 1;
}
std::cout << "mkfifo success" << std::endl;
//管道不同于普通文件的一个特性:
//打开文件,write方没有执行open的时候,如果先调度read方,则read方就会在open内部进行阻塞
//直到有write方把管道文件打开,read方的open才会返回!
//(判断read方还是write方:由open的第二个参数flags决定)
//而普通文件只要文件被创建了,如何一方都可以随时打开
// 2. 打开管道文件(阻塞等待客户端连接)
// 打开命名管道
int fd = open(FIFO_FILE, O_RDONLY);
if (fd < 0)
{
std::cout << "server open fifo failed" << std::endl;
}
else
{
std::cout << "server open fifo success" << std::endl;
}
// 读取管道数据read
while (true)
{
char buffer[1024];
int number = read(fd, buffer, sizeof(buffer) - 1);
if(number > 0)
{
buffer[number] = 0; //结尾带上\0形成字符串
std::cout << "Client say# " << buffer << std::endl;
}
else if(number == 0)
{
//写端退出->读端read返回0,读到文件末尾,也需要进行退出
std::cout << "Client quit! me too!" << std::endl;
break;
}
else
{
std::cerr << "read error" << std::endl;
break;
}
}
//关闭文件描述符
close(fd);
// 系统调用:删除管道unlink
// int unlink(const char *pathname);
int dele = unlink(FIFO_FILE);
if (dele == 0)
{
std::cout << "remove mkfifo success" << std::endl;
}
else
{
std::cout << "remove mkfifo failed" << std::endl;
}
return 0;
}
客户端程序(client.cc):
cpp
#include <iostream>
#include "comm.hpp"
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
// client负责写入数据
int main()
{
// 1. 以写方式打开管道(阻塞,直到服务端打开读端)
// 打开命名管道fifo
int fd = open(FIFO_FILE, O_WRONLY);
if (fd < 0)
{
std::cout << "client open fifo failed" << std::endl;
}
std::cout << "client open fifo success" << std::endl;
// 2. 循环输入并发送消息给服务端
//获取信息
pid_t id = getpid(); //获取当前进程pid
int cnt = 1;
// 写入数据
while (true)
{
std::cout << "Please enter# ";
std::string message;
getline(std::cin, message); //按行读取字符串
message += (", message number: " + std::to_string(cnt++) + " [" + std::to_string(id) + "]");
//写入message到管道fifo
write(fd, message.c_str(), message.size());
}
// 关闭文件描述符
close(fd);
return 0;
}
comm.h:
cpp
#pragma once
#define FIFO_FILE "fifo"
编译与运行:

必须先打开服务端再打开客服端
原因是我们是在服务端创建的管道,只有管道存在的情况下,一端打开管道才会进行阻塞状态,等待另一端打开管道;而如果本身管道就不存在,直接open打开则会返回-1打开失败。

4.1.2 版本二(优化)
comm.h:
cpp
#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
// #define FIFO_FILE "fifo"
// 错误处理宏
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0) // \->续行符,实际为一行代码
// 管道的创建和删除
class NameFifo
{
public:
NameFifo(const std::string path, const std::string name)
: _path(path), _name(name)
{
// 创建管道
_fifoname = path + "/" + name;
umask(0); // 默认umask为0002,修改umask为0,保证权限设置一一对应
// 1、创建命名管道fifo
// int mkfifo(const char *pathname, mode_t mode);
int n = mkfifo(_fifoname.c_str(), 0666); // 第二个参数就是传权限位mode
if (n < 0)
{
ERR_EXIT("mkfifo");
}
else
{
std::cout << "mkfifo success" << std::endl;
}
}
~NameFifo()
{
// 删除管道
// 系统调用:删除管道unlink
// int unlink(const char *pathname);
int dele = unlink(_fifoname.c_str());
if (dele == 0)
{
std::cout << "remove mkfifo success" << std::endl;
}
else
{
std::cout << "remove mkfifo failed" << std::endl;
}
}
private:
std::string _path;
std::string _name;
std::string _fifoname;
};
// 读写文件的操作
class FileOper
{
public:
FileOper(const std::string path, const std::string name)
: _path(path), _name(name), _fd(-1)
{
_fifoname = path + "/" + name;
}
void OpenforRead()
{
// 管道不同于普通文件的一个特性:
// 打开文件,write方没有执行open的时候,如果先调度read方,则read方就会在open内部进行阻塞
// 直到有write方把管道文件打开,read方的open才会返回!
//(判断read方还是write方:由open的第二个参数flags决定)
// 而普通文件只要文件被创建了,如何一方都可以随时打开
// 2. 以读的方式打开管道文件(阻塞等待客户端连接)
// 打开命名管道
_fd = open(_fifoname.c_str(), O_RDONLY);
if (_fd < 0)
{
ERR_EXIT("open_read");
}
else
{
std::cout << "server open fifo success" << std::endl;
}
}
void OpenforWrite()
{
// 1. 以写方式打开管道(阻塞,直到服务端打开读端)
// 打开命名管道fifo
_fd = open(_fifoname.c_str(), O_WRONLY);
if (_fd < 0)
{
ERR_EXIT("open_write");
}
else
{
std::cout << "client open fifo success" << std::endl;
}
}
void Read()
{
// 读取管道数据read
while (true)
{
char buffer[1024];
int number = read(_fd, buffer, sizeof(buffer) - 1);
if (number > 0)
{
buffer[number] = 0; // 结尾带上\0形成字符串
std::cout << "Client say# " << buffer << std::endl;
}
else if (number == 0)
{
// 写端退出->读端read返回0,读到文件末尾,也需要进行退出
std::cout << "Client quit! me too!" << std::endl;
break;
}
else
{
ERR_EXIT("read");
}
}
}
void Write()
{
// 2. 循环输入并发送消息给服务端
// 获取信息
pid_t id = getpid(); // 获取当前进程pid
int cnt = 1;
// 向管道写入数据
while (true)
{
std::cout << "Please enter# ";
std::string message;
getline(std::cin, message); // 按行读取字符串
message += (", message number: " + std::to_string(cnt++) + " [" + std::to_string(id) + "]");
// 写入message到管道fifo
write(_fd, message.c_str(), message.size());
}
}
// 关闭文件描述符
void Close()
{
if (_fd > 0)
{
close(_fd);
}
}
private:
std::string _path;
std::string _name;
std::string _fifoname;
int _fd;
};
服务端程序(server.cc):
cpp
#include "comm.hpp"
// server负责创建命名管道和读取数据
int main()
{
//创建管道
NameFifo fifo(".", "fifo");
//以读的方式打开管道
FileOper readerfile(".", "fifo");
readerfile.OpenforRead();
//向管道读取数据
readerfile.Read();
//关闭文件描述符
readerfile.Close();
//进程结束自动调用NameFifo析构函数,删除管道
return 0;
}
客户端程序(client.cc):
cpp
#include "comm.hpp"
// client负责写入数据
int main()
{
// 以写的方式打开管道
FileOper writerfile(".", "fifo");
writerfile.OpenforWrite();
// 向管道写入数据
writerfile.Write();
// 关闭文件描述符
writerfile.Close();
return 0;
}
4.2 案例 2:命名管道实现文件拷贝
通过两个程序配合,实现文件拷贝功能:
- **file_writer.cc:**读取本地文件,将内容写入命名管道;
- **file_reader.cc:**从命名管道读取内容,写入目标文件。
写端程序(file_writer.c):
cpp
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string>
// 错误处理宏
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main()
{
// 1. 创建命名管道
umask(0);
int n = mkfifo("tp", 0666);
if (n < 0)
{
ERR_EXIT("mkfifo error");
}
// 2. 打开已存在的本地文件(待拷贝的源文件abc)
int infd = open("abc", O_RDONLY);
if (infd < 0)
{
ERR_EXIT("open source file error");
}
// 3. 以写方式打开命名管道(阻塞,直到读端打开)
int outfd = open("tp", O_WRONLY);
if (outfd < 0)
{
ERR_EXIT("open fifo error");
}
// 4. 读取源文件内容,写入管道
while(true)
{
char buffer[1024];
int n = read(infd, buffer, 1024);
if(n == 0) break;
write(outfd, buffer, n);
}
// 5. 关闭文件描述符
close(infd);
close(outfd);
printf("文件内容写入管道完成\n");
return 0;
}
读端程序(file_reader.c):
cpp
#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string>
// 错误处理宏
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while (0)
int main()
{
umask(0);
// 1. 以读方式打开命名管道(阻塞,直到写端打开)
int infd = open("tp", O_RDONLY);
if (infd < 0)
{
ERR_EXIT("open fifo error");
}
// 2. 创建目标文件(拷贝后的文件abc.bak)
int outfd = open("abc_bak", O_WRONLY | O_CREAT | O_TRUNC, 0666);
if (outfd < 0)
{
ERR_EXIT("open target file error");
}
// 3. 从管道读取内容,写入目标文件
while(true)
{
char buffer[1024];
int n = read(infd, buffer, 1024);
if(n == 0) break;
write(outfd, buffer, n);
}
// 4. 关闭文件描述符,删除命名管道
close(infd);
close(outfd);
unlink("tp"); // 手动删除管道文件
printf("文件拷贝完成\n");
return 0;
}
编译与运行:
makefile:
cpp
.PHONY:all
all:file_reader file_writer
file_reader:file_reader.cc
g++ -o $@ $^ -std=c++11
file_writer:file_writer.cc
g++ -o $@ $^ -std=c++11
.PHONY:clean
clean:
rm -f file_reader file_writer

运行结果:
- 写端读取
abc文件内容,写入命名管道tp; - 读端从
tp读取内容,写入abc.bak; - 拷贝完成后,读端删除管道文件,两个程序退出。
五. 命名管道使用总结
- 必须手动删除管道文件 :命名管道创建后会残留于文件系统,若不删除,下次创建会报错(errno=EEXIST),建议在通信结束后用unlink()删除;
- 避免单进程同时读写 :虽然可通过O_RDWR打开管道实现单进程读写,但会破坏半双工特性,容易导致数据混乱;
- 处理阻塞场景 :读端未打开时写端会阻塞,写端未打开时读端会阻塞,若需非阻塞操作,可在open() 时添加O_NONBLOCK标志;
- 数据完整性保证 :当写入数据量 ≤ PIPE_BUF(默认 4096 字节)时,内核保证写入原子性;超过则不保证,需在应用层处理分包;
- 权限设置合理:创建管道时权限需开放给通信进程(如 0664 允许同组进程访问),避免因权限不足导致open()失败。
总结 :命名管道(FIFO)是匿名管道的重要扩展,其核心价值在于突破了亲缘进程的限制,通过文件系统路径实现任意进程间的通信,且沿用了 Linux 标准的文件操作接口,上手成本低。
- 命名管道是带文件路径的内核缓冲区,支持跨进程通信
- 需通过mkfifo() 或mkfifo命令创建,open()时需遵循读 / 写端同步规则;
- 实战中可实现文件拷贝、C/S 通信等场景,配合**read()/write()**即可完成数据传输;
- 与匿名管道相比,命名管道的核心优势是通信范围无限制,生命周期随内核。
结束语
到这里,关于命名管道(FIFO) 的核心知识、原理、实战与优化就全部讲解完毕了。我们从修复匿名管道进程池的隐蔽问题出发,一步步认识了命名管道的本质 ------带文件路径的内核缓冲区,它打破了亲缘进程的限制,让任意无关进程都能安全通信。从概念、创建、打开规则,到可直接运行的服务端 / 客户端通信、文件拷贝实战,再到面向对象封装优化,我们完整走完了命名管道的学习与实践全流程。
