- 熟练使用pipe进行父子进程间通信
- 熟练使用pipe进行兄弟进程间通信
- 熟练使用fifo进行无血缘关系的进程间通信
- 使用mmap进行有血缘关系的进程间通信
- 使用mmap进行无血缘关系的进程间通信
Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
管道-pipe
- 函数作用:
创建一个管道
- 函数原型:
int pipe(int fd[2]);
- 函数参数:
若函数调用成功,fd[0]存放管道的读端,fd[1]存放管道的写端
- 返回值:
- 成功返回0;
- 失败返回-1,并设置errno值。
函数调用成功返回读端和写端的文件描述符,其中fd[0]是读端, fd[1]是写端,向管道读写数据是通过使用这两个文件描述符进行的,读写管道的实质是操作内核缓冲区。
创建步骤总结:
- 父进程调用pipe函数创建管道,得到两个文件描述符fd[0]和fd[1],分别指向管道的读端和写端。
- 父进程调用fork创建子进程,那么子进程也有两个文件描述符指向同一管。
- 父进程关闭管道读端,子进程关闭管道写端。父进程可以向管道中写入数据,子进程将管道中的数据读出,这样就实现了父子进程间通信。
如何设置管道为非阻塞
默认情况下,管道的读写两端都是阻塞的,若要设置读或者写端为非阻塞,则可参
考下列三个步骤进行:
第1步: int flags = fcntl(fd[0], F_GETFL, 0);
第2步: flag |= O_NONBLOCK;
第3步: fcntl(fd[0], F_SETFL, flags);
若是读端设置为非阻塞:
- 写端没有关闭,管道中没有数据可读,则read返回-1;
- 写端没有关闭,管道中有数据可读,则read返回实际读到的字节数
- 写端已经关闭,管道中有数据可读,则read返回实际读到的字节数
- 写端已经关闭,管道中没有数据可读,则read返回0
如何查看管道缓冲区大小
- 命令
ulimit -a
- 函数
long fpathconf(int fd, int name);
printf("pipe size==[%ld]\n", fpathconf(fd[0], _PC_PIPE_BUF));
printf("pipe size==[%ld]\n", fpathconf(fd[1], _PC_PIPE_BUF));
创建管道
- 方式1-使用命令 mkfifo
命令格式: mkfifo 管道名
例如:mkfifo myfifo
- 方式2-使用函数
int mkfifo(const char *pathname, mode_t mode);
参数说明和返回值可以查看man 3 mkfifo
当创建了一个FIFO,就可以使用open函数打开它,常见的文件I/O函数都可用于FIFO。如:close、read、write、unlink等。
FIFO严格遵循先进先出(first in first out),对FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作
mmap函数
- 函数作用:
建立存储映射区
- 函数原型
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
- 函数返回值:
- 成功:返回创建的映射区首地址;
- 失败:MAP_FAILED宏
- 参数:
- addr: 指定映射的起始地址, 通常设为NULL, 由系统指定
- length:映射到内存的文件长度
- prot: 映射区的保护方式, 最常用的:
- 读:PROT_READ
- 写:PROT_WRITE
- 读写:PROT_READ | PROT_WRITE
- flags: 映射区的特性, 可以是
- MAP_SHARED: 写入映射区的数据会写回文件, 且允许其他映射该文件的进程共享。
- MAP_PRIVATE: 对映射区的写入操作会产生一个映射区的复制(copy-on-write), 对此区域所做的修改不会写回原文件。
- fd:由open返回的文件描述符, 代表要映射的文件。
- offset:以文件开始处的偏移量, 必须是4k的整数倍, 通常为0, 表示从文件头开始映射。
- munmap函数
- 函数作用:
释放由mmap函数建立的存储映射区
- 函数原型:
int munmap(void *addr, size_t length);
- 返回值:
成功:返回0
失败:返回-1,设置errno值
- 函数参数:
- addr:调用mmap函数成功返回的映射区首地址
- length:映射区大小(mmap函数的第二个参数)