进程间通信机制(一)管道

一、基础概念:

linux下进程间通信:也叫做 IPC
常见的IPC方法:
1.管道:有名管道(用于非血缘关系进程)和匿名管道;
2.信号:
3.共享内存:也叫共享映射,用于非血缘关系进程
4.消息队列
5.套接字

早期进程间通信还会使用文件,虽然每个进程地址空间独立,但是1G大小的内核空间是共享的,所以两个进程共享一个文件,就达到了进程通信的目的。

为什么要进程间通信
因为每个进程都有自己独立的地址空间,进程中的数据都是进程私有的。

二、管道的概念:
1.管道的特质:

1.本质上是一个伪文件(实际上是内核的一小块缓冲区),利用缓冲区实现的伪文件
2.由2个文件描述符引用这个伪文件,一个表示读端,一个表示写端
3.规定,数据从写端流入,从读端流出

所以说,管道的同步是自带的,文件在磁盘上上存在,只不过数据是在内存上
所以查看管道文件的大为0

2.什么是伪文件:

linux下的文件种类:
占用磁盘空间:-文件 d目录  l符号链接
不占磁盘空间:s套接字 b块设备 c字符设备 p管道

不占用磁盘空间的文件,但是在磁盘上有记录 就叫做伪文件

3.管道实现原理:
内核使用一个环形队列机制实现充当一个缓冲区,默认大小为4K

king@ubuntu:~$ ulimit -al
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7703
max locked memory       (kbytes, -l) 16384
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8    //8个扇区,一个扇区512B
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7703
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

既然是一个队列,就有队列的特点:FIFO,现进先出
4.使用管道的注意事项(局限性):

1.数据自己读不能自己写
2.数据一旦被读走,数据便不在管道中存在,不可反复读取
3.由于管道采用半双工的通信方式,数据只能在一个方向上流动
4.管道只能在公共祖先的进程间使用管道,也就是只能在本机上通信

5.通信方式:

单工通信:不管什么时刻,只能固定一头读,固定一头写
半双工通信:要么一头读,一头写,不能一头又读又写
全双工通信:两头既可以同时读写

三、管道的使用:

1.无名管道(匿名管道):只能用于父子进程之间

#include
int pipe(int pipefd[2]);

fd[0]:读端
fd[1]:写端

返回值成功返回0 失败返回-1

实现一个管道,完成父子进程间通信

#include
#include
#include
#include

int main()
{
	int fd[2]; //定义一个文件描述符数组,保存管道两端的文件描述符
	int ret = pipe(fd);
	if( ret == -1 )
	{
		perror();
	}
	pid_t pid = fork();
}
。。。。。。。。。

剩下的代码我先不写,我们来观察一个现象,我们通过pipe()创建了一个管道,并且得到了两个文件描述符,fd[0]和fd[1],当然相当于父进程中两个,子进程中也有两个。

进程间通信机制(一)管道_第1张图片
所以需要进行以下的操作: 我们把程序补充完整:
保证管道的单向性,写端关闭读端,读端关闭写端。
进程间通信机制(一)管道_第2张图片

#include
#include
#include
#include

int main()
{
	int fd[2]; //定义一个文件描述符数组,保存管道两端的文件描述符
	int ret = pipe(fd);
	if( ret == -1 )
	{
		perror("pipe failed");
	}
	pid_t pid = fork();
	if( pid == 0 )  //子进程读数据,所以关闭写端
	{
		close(fd[1]);
		char buff[1024] = {0};
		ret = read(fd[0],buff,sizeof(buff));

		write(1,buff,ret);
	
	}
	else if(pid > 0)//父进程进行写数据,所以关闭读端
	{
		close(fd[0]);
		write(fd[1],"hello world\n",strlen("hello world\n"));
	}

	return 0;
}
执行结果:
hello world

读时注意事项:

1.管道有数据
read返回实际读到的数据个数

2.管道无数据
判断写端是否关闭,read返回0
写端开着,认为不久的将来会给管道中写数据,所以读端一直阻塞着

写时注意事项:

1.读端全关闭
进程异常终止,SIGPIPE信号

2.有读端打开
管道未满,写数据,write返回写入字节数
管道写满,阻塞,直到有空间腾出来

2.命名管道:fifo 无血缘关系的进程间可以使用
进程间通信机制(一)管道_第3张图片
在这里插入图片描述
命名管道的读端:
进程间通信机制(一)管道_第4张图片
命名管道的写端:
进程间通信机制(一)管道_第5张图片
这个代码是以前写的,需要注意的是,命名管道创建好以后,进程之间通信时要使用同一个目录下的fifo文件,否则无法实现。也支持多读端多写端

你可能感兴趣的:(linux)