IPC进程间通信
大概有三四种方式。
对于之前的:opt=WNOHANG,表示非阻塞。
进程间通信基本概述:
多个进程之间建立信道,实现跨进程传递收发消息的技术。
socket也是一种进程间通信技术,网络通信也是进程间通信技术。两个进程之间的交互。
各种和系统都有对这类技术的兼容与实现,IPC是进程间通信的缩写。
IPC:匿名管道(PIPE)、有名管道(FIFO)、内存共享映射(MMAP)、信号(SIGNAL)、Unix Domain Socket(本地套接字)、SYSTEMV消息队列、POSIX消息队列。
传统的socket是网卡,但是本地的不走网卡,不走网络层,可以做独立的进程通信,局域网中可以使用,但是传统公网不能用。
消息队列,有两种:SYSTEMV消息队列、POSIX消息队列。但是不提,就是一些函数。
细说进程通信原理
多个进程交互数据,但是进程间通信的位置在哪?
以后的进程通信技术,都要确定位置,一个进程由两块空间:用户、核心。
使用内核层实现进程通信。
进程通信利用的是内核层(共享内存)实现的,用户层不能通信,每个人的用户层都是独立的,互相不能看见。
但是内核层,空间都是一块地址,就有了交互、交换数据的可能。
内核层共享地址。
例如放入一个数据包在内核层,那么其他进程也能看到,用户层就不可能看到,每个人都是独立的。
进程通信基于内核空间共享模式。
匿名管道(PIPE)
管道特征
- 数据流通性
- 方向性,数据流通是有方向的。
- 可以暂存数据内容
综上是最基本的特征。
管道用法
Linux管道创建函数:pipe函数
int pipe(int fds[2]),先定义一个数组,然后把数组传进去。
调用该函数就能创建匿名管道了。
匿名管道的形态及传输过程
两个进程AB,管道是由一个进程创建的,想让两个进程通信,只需要一个进程创建管道即可,而不是两个人都创建。
假设A去创建,调用pipe函数,传入fds数组。
调用之后,就会在两个内核层之间创建:管道缓冲区。
管道缓冲区的数据结构是:环形队列。管道缓冲区的大小:4K。
管道缓冲区怎么用?肯定是读写。
管道有两端,一端是读端,一端是写端。
R端和W端。
数据传出之后呢,有两个数据:fds[0]和fds[1],0是R,1是W。
R指向0,1指向W。读数据用0,写数据用1。
另外一个进程?
首先如果要用管道,就必须得到fds0和1,才能访问;
进程B是不能再次创建管道,这样自己玩自己的,就无法通信了。
我们要通信,必须是两个进程用一个管道,以管道作为媒介进行通信。
那么B如何读到fds变量?你用户层的东西是无法读到的,但是有一种情况是里外的:子进程是可以的,因为直接继承。
也是R指向0,1指向W。
因此!匿名管道只能完成父子进程之间的通信。
这也是缺点。你必须继承才行,如果是两个不相干的进程,是不能用匿名管道的。
匿名管道只能完成亲缘进程间通信。
要定好谁来读,谁来写,要确定传输方向。父写子读,还是子写父读。
定好之后,每个进程都是有一个0和一个1的,也就是4个。
定好了之后,例如是父写子读,那么就要关闭父亲的0和孩子的1端。4个砍掉两个,才是真正的实施措施。
管道用完了,一定要关掉!要成习惯,close(fds[1]);
应该是先pipe,然后再fork。
也就是说,定好了父写,就是父亲传入内容,然后在子进程中,进行读取。
其中bzero就是给初始值进行一个清零。
管道的访问方式:读写端。
要确定:传输方向。
单工、双工、半双工
单工通信:单行道,一个通信方向,方向不可改变。
同一时刻只能非读即写。不允许切换通信方向。
半双工通信:也是单行道,但是不同时刻可以切换方向。
半双工也是单工,可调节单工。
全双工(双工):同一时刻同时读写,socket就是双工。
上行速度、下载速度,就是双工。
管道使用的注意事项(缺点)
- 管道销毁释放,管道队列占用内核空间,如何释放?所有访问管道的描述符全部关闭(close)内核会自行释放管道内存
- 匿名管道使用时为单工通信
- 只支持亲缘进程间通信
- 匿名管道数据传输时,采用无格式字节流,用户需要自行封装数据包。
例如,应用层协议包,协议编号、协议类型、确认报文、验证码、消息内容。固定4K
无论消息是什么,但是包大小都相同。
消息类型、消息内容。大概是结构体的样子。
优点:用起来简单,效率高,适合数字通信。
匿名管道使用时的特殊情况(具有普遍意义的)
很多的特殊情况都这4中情况:
- 写端未向管道写数据,管道为NULL,读端读取管道阻塞
- 读端未读管道数据,管道为满,写端写管道产生阻塞
- 写端关闭,读端读取完管道剩余数据后,再次读时,返回0,也就是说,以后读端读到数据是0了,那就说明写端关闭了
- 读端关闭,写端向管道写数据,内核向写端进程发送SIGPIPE,杀死写端进程
开发了服务器和客户端,客户端向服务器发送请求数据,而后客户端异常退出了,服务端接收处理请求后,向客户端发送响应,结果服务端也异常退出了,为什么?
服务端是写端,读端关闭了,那么写端也关闭了。服务端就是被SIGPIPE杀死的。
有名管道(FIFO)
也叫命名管道。
命名管道使用要先创建出管道文件:
命令创建:mkfifo xxx
函数创建:mkfifo("xxx", 0064)权限,unlink("xxx")
黑底黄字的文件,是管道文件prw-rw-r--这种。
有名管道将内核缓冲区实体化变为管道文件,多个进程可以利用管道文件的读写,完成进程间通信(无亲缘你关系进程间通信)
有名管道使用逻辑
两个进程:读和写。读写之间有p类型的管道文件,write在open的时候会产生阻塞,写的时候是WRONLY,读的时候是RDONLY,这就相当于两个钥匙。
进程要访问使用管道文件,必须集齐两种访问权限(RD/WR)才可以成功打开管道并使用,否则就会阻塞,阻塞到另外一把钥匙过来为止。等待另一种权限。
但是O_RDWR这种一个人就可以打开。
管道文件
管道文件属于设备文件,dev当中的,与常规文件不同,不可编辑,也不会分配磁盘,它不能存储数据。
打开之后啥也没有,不能编辑、退出,要打开了就得关闭终端。
管道文件与内核缓冲区的关系
管道文件是和内核缓冲区绑定的,管道缓冲区:环形队列、暂存数据、4K大小。
管道文件就是管道缓冲区的指针,所以说不能存东西。
你在R或W的时候都是先通过管道文件,然后到管道缓冲区找到文件,而不是直接对管道进行操作。你都是在操作:管道缓冲区。
p和管道缓冲区bind了。
删除命名管道文件后,对应的管道缓冲区也会被释放。