Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
在进程间完成数据传递需要借助操作系统提供特殊的方法,如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的蓬勃发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有:
① 管道 (使用最简单)
② 信号 (开销最小)
③ 共享映射区 (无血缘关系)
④ 本地套接字 (最稳定)
管道
未名管道(匿名管道)
管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
1. 其本质是一个伪文件(实为内核缓冲区)
linux文件类型:- 文件 d 目录 l 符号链接
s 套接字 b块设备 c 字符设备 p 管道 (这四种都是伪文件)
- 由两个文件描述符引用,一个表示读端,一个表示写端。
- 规定数据从管道的写端流入管道,从读端流出。
管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。
管道的局限性:
① 数据自己读不能自己写。
② 数据一旦被读走,便不在管道中存在,不可反复读取。
③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
④ 只能在有公共祖先的进程间使用管道。(有血缘关系的进程)
常见的通信方式有,单工通信、半双工通信、全双工通信。
pipe函数
创建管道
int pipe(int pipefd[2]); 成功:0;失败:-1,设置errno
函数调用成功返回r/w两个文件描述符。无需open,但需手动close。规定:fd[0] → r; fd[1] → w,就像0对应标准输入,1对应标准输出一样。向管道文件读写数据其实是在读写内核缓冲区。
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int fd[2];
int ret =0;
ret = pipe(fd);
pid_t pid;
if(ret == -1)
{
perror("pipe error.\n")
exit(1);
}
pid = fork();
if(pid == -1)
{
perror("fork error.\n");
exit(1);
}
else if(pid ==0)
{
close(fd[1]);//子进程负责读,所以关闭写的描述符
char buf[1024];
ret = read(fd[0],buf,sizeof(buf));//从管道读数据
if(ret == 0)
{
printf("end.\n");
}
write(STDOUT_FILENO,buf,ret);//写到屏幕
}
else
{
close(fd[0]);//父进程负责写,所以关闭读的描述符
char *str ="hello ,pipe.";
write(fd[1],str,strlen(str));
}
return 0;
}
FIFO
命名管道
FIFO常被称为命名管道,以区分管道(pipe)。管道(pipe)只能用于“有血缘关系”的进程间。但通过FIFO,不相关的进程也能交换数据。
FIFO是Linux基础文件类型中的一种。但,FIFO文件在磁盘上没有数据块,仅仅用来标识内核中一条通道。各进程可以打开这个文件进行read/write,实际上是在读写内核通道,这样就实现了进程间通信。
创建方式:
1. 命令:mkfifo 管道名
2. 库函数:int mkfifo(const char *pathname, mode_t mode); 成功:0; 失败:-1
一旦使用mkfifo创建了一个FIFO,就可以使用open打开它,常见的文件I/O函数都可用于fifo。如:close、read、write、unlink等。
有名管道的打开规则:
有名管道比无名管道多了一个打开操作:open
FIFO的打开及读写规则:
一、对于FIFO,需要open去打开FIFO的读端或是写端的描述符。
1> 如果open的时候没有指定O_NONBLOCK标志,且open的是读端时
如果不存在此FIFO的已经打开的写端时,open会一直阻塞到有FIFO的写端打开;
如果已经存在此FIFO的打开的写端时,open会直接成功返回。
2> 如果open的时候没有指定O_NONBLOCK标志,且open的是写端时
如果不存在此FIFO的已经打开的读端时,open会一直阻塞到有FIFO的读端打开;
如果已经存在此FIFO的打开的读端时,open会直接成功返回。
二、从FIFO或者空管道读写
1> read时,读端fd没有指定O_NONBLOCK标志
如果存在此FIFO或管道的已经打开的写端时,阻塞到FIFO或管道中有数据或者FIFO或管道的已经打开的写端全部被关闭为止。
如果不存在此FIFO或管道的已经打开的写端时,read返回0;
2> write时, 同read差不多,就不详述了。