云计算百科
云计算领域专业知识百科平台

Linux进程通信——管道

目录

1 匿名管道

1.1 创建匿名管道

1.1.1 pipe

1.2 匿名管道的使用

1.3 内核实现原理

1.3.1 内核数据结构

1.3.2 数据流动过程

1.3.3 阻塞与非阻塞

1.4 管道的五大特性和四种情况

2 命名管道

2.1 创建命名管道

2.1.1 mkfifo

2.2 命名管道的使用

2.3 命名管道的原理

2.4 删除命名管道


管道是一个非常古老的进程通信的方式。管道允许两个相关进程(通常是父子进程)通过一个单向或双向的数据通道交换数据

管道是一个基于文件系统的一个内存级的单向通信的文件,主要用来进行进程通信(IPC)

(1)管道使用样例

lz@VM-8-15-ubuntu:~/learn$ ls -l | grep pipe

1 匿名管道


匿名管道(Anonymous Pipe)是 Linux 中一种经典的 进程间通信(IPC) 机制,主要用于 父子进程 或 兄弟进程 之间的单向数据通信。其核心特点是 内存级高效传输、内核缓冲区管理 和 半双工通信

1.1 创建匿名管道

1.1.1 pipe

(1)功能

用于创建一个 匿名管道(Anonymous Pipe),实现父子进程间的单向通信

(2)函数原型

#include <unistd.h>
int pipe(int pipefd[2]);

(3)参数

  • pipefd[2]:长度为 2 的整型数组,用于返回两个文件描述符:
    • pipefd[0]:管道的 读端(用于 read())。
    • pipefd[1]:管道的 写端(用于 write())。

(4)返回值

成功返回 0,失败返回 -1 并设置 errno。

1.2 匿名管道的使用

(1)父进程读数据,子进程写数据

#include <cstdio>
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main()
{
// 创建管道
int pipefd[2];
int n=pipe(pipefd);
// 创建子进程
pid_t pid = fork();
// 通信
if(pid == -1)
{
perror("fork");
return 1;
}
else if(pid == 0)
{
// 关闭读端
close(pipefd[0]);
// 子进程
int cnt=1;
while(1)
{
// 写入数据
std::string msg="my child process, pid = ";
msg+=std::to_string(pid);
msg += ", content = ";
msg+=std::to_string(cnt);
cnt++;

// 写入管道
int n = write(pipefd[1],msg.c_str(),msg.size());
sleep(1);
}
}
else
{
// 关闭写端
close(pipefd[1]);
// 父进程
char buff[1024]={0};
while(1)
{
// 读取数据
int n=read(pipefd[0],buff,sizeof(buff)-1);
buff[n]='\\0';
std::cout<<buff<<std::endl;
sleep(1);
}
}
// 等待子进程
pid_t status=waitpid(pid,NULL,0);
return 0;
}

注意事项:

(1)必须关闭未使用的端:

  • 父进程不关闭读端 → 写满管道后 write() 阻塞。
  • 子进程不关闭写端 → 读空管道时 read() 不会返回 EOF(返回0)。

(2)创建管道需要在创建子进程前,才能保证子进程与父进程通信的是同一个管道

(3)管道是字节流,无消息边界

1.3 内核实现原理

1.3.1 内核数据结构

管道在内核中由 pipe_inode_info 管理

struct pipe_inode_info {
struct page *pages[PIPE_DEF_BUFFERS]; // 环形缓冲区(默认16页)
unsigned int head; // 写指针
unsigned int tail; // 读指针
unsigned int readers; // 读端引用计数
unsigned int writers; // 写端引用计数
wait_queue_head_t wait; // 阻塞等待队列
// …
};

1.3.2 数据流动过程

(1)写入数据(write(fd[1], buf, size)):

  • 检查缓冲区剩余空间,不足则阻塞(除非 O_NONBLOCK)。
  • 数据从用户空间拷贝到内核环形缓冲区。
  • 更新 head 指针,唤醒等待读的进程。

(2)读取数据(read(fd[0], buf, size)):

  • 检查缓冲区数据量,为空则阻塞(除非 O_NONBLOCK)。
  • 数据从内核缓冲区拷贝到用户空间。
  • 更新 tail 指针,唤醒等待写的进程。

1.3.3 阻塞与非阻塞

(1)阻塞模式(默认):

  • 读空管道时,read() 阻塞,直到有数据或写端关闭。
  • 写满管道时,write() 阻塞,直到有空间。

(2)非阻塞模式

fcntl(pipefd[0], F_SETFL, O_NONBLOCK); // 读端非阻塞
fcntl(pipefd[1], F_SETFL, O_NONBLOCK); // 写端非阻塞

  • 读空管道时,read() 返回 -1,errno=EAGAIN。
  • 写满管道时,write() 返回 -1,errno=EAGAIN。

1.4 管道的五大特性和四种情况

(1)五大特性

  • 常用于具有血缘关系的进程进行PIC
  • 单向通信
  • 匿名管道的生命周期随进程
  • 匿名管道是面向字节流的
  • 管道自带同步机制

(2)四种情况

  • 写端不关,写端不写——管道里没有数据,读端就会处于阻塞状态
  • 读端不关,读端不读——写端写满管道,就不会进行写入
  • 写端不写,写端关闭——读端不会读到数据,read的返回值为0表示已经读到文件结尾
  • 写端写入,读端关闭——操作系统会自动结束写端进程

2 命名管道


命名管道(Named Pipe,也称为 
FIFO
,即 
First In First Out
)是 Linux 中一种进程间通信(IPC, Inter-Process Communication)的方式。

它类似于匿名管道(
|

  • 匿名管道 只能在父子进程或相关进程之间使用。
  • 命名管道 通过文件系统中的一个特殊文件(FIFO 文件)进行通信,允许 无关联的进程 进行数据交换。

FIFO(命名管道)与pipe(匿名管道)之间唯⼀的区别在它们创建与打开的⽅式不同,⼀但这些⼯作完成之后,
它们具有相同的语义。命名管道主要解决毫无关系的进程之间,进行文件级进程通信

2.1 创建命名管道

(1)命令行创建

// 使用 mkfifo 命令创建 FIFO 文件
mkfifo mypipe
// 使用 mkfifo 命令创建 FIFO 文件,指定权限(如 660)
mkfifo -m 660 mypipe

2.1.1 mkfifo

(1)功能

mkfifo 用于创建一个 FIFO(命名管道),它是一种特殊的文件类型,允许不同进程通过文件系统进行通信。FIFO 遵循先进先出(First In First Out)原则。

(2)函数原型

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

int mkfifo(const char *pathname, mode_t mode);

(3)参数

  • pathname : 创建的有名管道的名字
  • mode : 创建文件的权限

(4)返回值

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

2.2 命名管道的使用

命名管道的使用本质就是对一个打开的文件进行操作

示例一:⽤命名管道实现 server(服务端) & client(客户端) 通信

有名管道的学习代码,使用有名管道简单的实现服务端和客户端的进程通信 · d2c9787 · lv-zhuo/AsCent – Gitee.com

2.3 命名管道的原理

(1)FIFO 是一种特殊的 文件类型,但 不存储实际数据,仅作为数据通道。

(2)写入端 (>) 和读取端 (<) 必须同时存在,否则:

  • 如果只有写入端,写入操作会 阻塞,直到有进程读取。
  • 如果只有读取端,读取操作会 阻塞,直到有进程写入。

2.4 删除命名管道

(1)命令行删除

FIFO 文件只是普通文件,可以用 rm 删除

rm mkpipe

(1)功能

mkfifo 用于在当前目录下删除一个指定名字的文件

(2)函数原型

#include <fcntl.h>
#include <unistd.h>

int unlink(const char *pathname);

(3)参数

  • pathname : 删除文件的名字

(4)返回值

  • 成功返回 0,失败返回 -1 并设置 errno
赞(0)
未经允许不得转载:网硕互联帮助中心 » Linux进程通信——管道
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!