进程间通信的方式?
- - 管道
- - 匿名管道
- - 有名管道
- - 内存映射
- - 本地套接字
- - 网络套接字
- - 消息队列
- - 共享内存
- 父子进程始终共享什么东西?
- - 文件描述符
- - 内存映射区
目录
一、管道
管道的本质:
- 是内核缓冲区
- 拥有文件的特质(读操作、写操作)
- 匿名管道 -> 没有文件的实体
- 有名管道 -> 有文件实体, 不存储数据
- 可以文件操作的方式对管道进行处理
在创建子进程之前, 父进程通过文件操作打开了两个文件 a, b, 得到了两个文件描述符: fd3 fd4
父进程通过fork 创建子进程
子进程对应一个虚拟地址空间
- 文件描述符表: fd3, fd4 -> 从父进程拷贝过来的
- 在子进程中通过得到的fd3 fd4 来操作 A, B文件
1.1匿名管道
创建匿名管道
#include <unistd.h>
int pipe(int pipefd[2]); char*
参数:
pipefd: 传出参数
- pipefd[0] -> 管道的读端
- pipefd[1] -> 管道的写端
返回值:
0: 调用成功
-1: 失败
匿名管道的原理:
- 没有名字, 在磁盘上没有实体, 是内存中的一块缓冲区
- 这个缓冲区, 由父进程在fork()子进程之前创建得到的
- 内核缓冲区有两部分
- 读端 -> 可以进行读操作的文件描述符
- 写端 -> 可以进行写操作的文件描述符 - 父进程被销毁, 管道自动释放
- 默认阻塞
匿名管道数据结构是一个环形队列,默认容量4k
实现过程:
- - 读操作
- - 如果管道中有数据
- - read读, read返回值是读到的字节数
- - 管道中没有数据
- - 写端没有关闭, 但是写的慢,read会阻塞
- - 写端关闭了,read解除阻塞, 返回值为0
- - 如果管道中有数据
- - 写数据
- - 管道有空间。接着写, 写满之后阻塞
- - 没有空间。直接阻塞
- - 写数据的时候, 读端关闭了
- - 管道破裂
- - 进程被 SIGPIPE 信号杀死
管道的读写两端都默认阻塞,如何设置为非阻塞呢?
// 使用 fcntl 函数
// 设置读端为非阻塞 -> fd[0]
int flag = fcntl(fd[0], F_GETFL)
flag |= O_NONBLOCK;
fcntl(fd[0], F_SETFL, flag);