Ipc
by
IPC 进程间通信
interprocess communication
1. pipe 管道
管道的特质
管道是一种最基本的IPC机制,也称匿名管道,应用于有血缘关系的进程之间,完成数据传递。
调用 pipe 函数即可创建一个管道
- 管道的本质是一块内核缓冲区
- 由两个文件描述符引用,一个表示读端,一个表示写端
- 规定数据从管道的写端流入管道,从读端流出
- 当两个进程都终结的时候,管道也自动消失
- 管道的读端和写端都是默认阻塞的
管道的原理
- 管道的实质是内核缓冲区,内部使用环形队列实现
- 默认缓冲区大小为4K,可以使用
ulimit -a
命令获取大小 - 实际操作过程中缓冲区会根据数据压力做适当调整
管道的局限性
- 数据一旦被读走,便不在管道中存在,不可反复读取
- 数据只能在一个方向上流动,若要实现双向流动,必须使用两个管道
- 只能在有血缘关系的进程间使用管道
创建管道
函数作用:创建一个管道
函数原型:
-
int pipe(int fd[2])
函数参数: -
若函数调用成功,fd[0] 存放管道的读端,fd[1] 存放管道的写端 返回值:
- 成功返回 0
- 失败返回 -1,并设置 errno 值
父子进程间通信
先使用 pipe 创建管道,再进行 fork 操作,根据情况关闭 读端–fd[0] 或写端–fd[1]
设置管道为非阻塞
int flag = fcntl(fd[0], F_GETFL); //获取当前文件状态标志
flag |= O_NONBLOCK; //添加非阻塞标志
fcntl(fd[0], F_SETFL, flag); //设置新的标志
2. fifo 管道
fifo 介绍
fifo 通常被称为命名管道,以区分管道(pipe)
通过 fifo 不相关的进程也能交换数据
fifo 创建管道
方式 1 - 使用命令 mkfifo
-
命令格式:mkfifo 管道名
- 例如
mkfifo myfifo
- 例如
方式 2 - 使用函数
int mkfifo(const char*pathname, mode_t mode)
- 参数说明和返回值参考
man 3 mkfifo
思路
-
进程A:
- 创建一个 fifo 文件:mkfifo命令或者使用mkfifo函数
- open fifo 文件,获得一个文件描述符 fd
- 写 fifo 文件 — write(fd,”xxx”,…)
- 关闭 fifo 文件 — close(fd)
-
进程B:
- 打开 fifo 文件,获得文件描述符 fd
- 读 fifo 文件 — read(fd, buf, sizeof(buf))
- 关闭 fifo 文件 — close(fd)
3. 共享映射区
存储映射I/O 使一个磁盘文件与存储空间中的一个缓冲区相映射,从缓冲区中取数据,就相当于读文件中的相应字节;将数据写入缓冲区,则会将数据写入文件。这样就可以在不使用 read 和 write 函数的情况下,使用地址(指针)完成I/O操作
mmap 函数
函数作用:建立存储映射区
函数原型:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数:
- addr:一般传NULL,表示让内核去指定一个内存起始地址
-
length:文件大小
- lseek 或者 stat 函数
-
prot:
-
PROT_READ PROT_WRITE PROT_READ PROT_WRITE
-
-
flags:
- MAP_SHARED:对映射区的修改会反映到文件中(可以对文件进行修改)
- MAP_PRIVATE:对映射区的修改不会对文件产生影响
-
fd:打开的文件描述符
- fd = open()
- offset:从文件的哪个位置开始映射,一般传0
munmap 函数
函数作用:
- 释放由
mmap
函数建立的存储映射区
函数原型:
int munmap(void *addr, size_t length)
返回值:
- 成功:返回 0
- 失败:返回-1,设置 errno 值
函数参数:
- addr:调用 mmap 函数成功返回的映射区首地址
- length:映射区大小(mmap函数的第二个参数)
匿名映射
mmap(NULL, 4096 ,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0)
- MAP_ANONYMOUS 必须与 MAP_SHARED 一起使用,而且 fd 指定为-1