IPC(进程间通信)详解
Linux环境下,进程地址空间相互独⽴,每个进程各⾃有不同的⽤户地址空间。任何⼀个进程的全局变量在另⼀个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据bi必须通过内核,在内核中开辟⼀块缓冲区,进程1把数据从⽤户空间放⾄内核缓冲区,进程2再从内核缓冲区把数据读⾛,内核提供的这种机制称为进程间通信(IPC InterProcess Communication)
⼆、进程间通信的7种⽅式
第⼀类:传统的Unix通信机制
1. 管道/匿名管道(pipe)
管道是半双⼯的,数据只能向⼀个⽅向流动;需要双⽅通信时,需要建⽴起两个管道。
只能⽤于⽗⼦进程或者兄弟进程之间(具有亲缘关系的进程);
单独构成⼀种独⽴的⽂件系统:管道对于管道两端的进程⽽⾔,就是⼀个⽂件,但它不是普通的⽂件,它不属于某种⽂件系统,⽽是⾃⽴门户,单独构成⼀种⽂件系统,并且只存在与内存中。
数据的读出和写⼊:⼀个进程向管道中写的内容被管道另⼀端的进程读出。写⼊的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
管道的实质:
管道的实质是⼀个内核缓冲区,进程以先进先出的⽅式从缓冲区存取数据,管道⼀端的进程顺序的将数据写⼊缓冲区,另⼀端的进程则顺序的读出数据。
该缓冲区可以看做是⼀个循环队列,读和写的位置都是⾃动增长的,不能随意改变,⼀个数据只能被读⼀次,读出来以后在缓冲区就不复存在了。
当缓冲区读空或者写满时,有⼀定的规则控制相应的读进程或者写进程进⼊等待队列,当空的缓冲区有新数据写⼊或者满的缓冲区有数据读出来时,就唤醒等待队列中的进程继续读写。
管道的局限:
管道的主要局限性正体现在它的特点上:
只⽀持单向数据流;
只能⽤于具有亲缘关系的进程之间;
没有名字;
管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配⼀个页⾯⼤⼩);
管道所传送的是⽆格式字节流,这就要求管道的读出⽅和写⼊⽅必须事先约定好数据的格式,⽐如多少字节算作⼀个消息(或命令、或记录)等等;
2. 有名管道(FIFO)
匿名管道,由于没有名字,只能⽤于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道(FIF
O)。
有名管道不同于匿名管道之处在于它提供了⼀个路径名与之关联,以有名管道的⽂件形式存在于⽂件系统中,这样,即使与有名管道的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过有名管道相互通信,因此,通过有名管道不相关的进程也能交换数据。值的注意的是,有名管道严格遵循先进先出(first in first out),对匿名管道及有名管道的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不⽀持诸如lseek()等⽂件定位操作。有名管道的名字存在于⽂件系统中,内容存放在内存中。
匿名管道和有名管道总结:
(1)管道是特殊类型的⽂件,在满⾜先⼊先出的原则条件下可以进⾏读写,但不能进⾏定位读写。
(2)匿名管道是单向的,只能在有亲缘关系的进程间通信;有名管道以磁盘⽂件的⽅式存在,可以实现本机任意两个进程通信。
(3)⽆名管道阻塞问题:⽆名管道⽆需显⽰打开,创建时直接返回⽂件描述符,在读写时需要确定对⽅的存在,否则将退出。如果当前进
程向⽆名管道的⼀端写数据,必须确定另⼀端有某⼀进程。如果写⼊⽆名管道的数据超过其最⼤值,写
操作将阻塞,如果管道中没有数据,读操作将阻塞,如果管道发现另⼀端断开,将⾃动退出。
(4)有名管道阻塞问题:有名管道在打开时需要确实对⽅的存在,否则将阻塞。即以读⽅式打开某管道,在此之前必须⼀个进程以写⽅式打开管道,否则阻塞。此外,可以以读写(O_RDWR)模式打开有名管道,即当前进程读,当前进程写,不会阻塞。
3. 信号(Signal)
信号是Linux系统中⽤于进程间互相通信或者操作的⼀种机制,信号可以在任何时候发给某⼀进程,⽽⽆需知道该进程的状态。
如果该进程当前并未处于执⾏状态,则该信号就有内核保存起来,知道该进程回复执⾏并传递给它为⽌。
如果⼀个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消是才被传递给进程。
Linux系统中常⽤信号:
(1)SIGHUP:⽤户从终端注销,所有已启动进程都将收到该进程。系统缺省状态下对该信号的处理是终⽌进程。
(2)SIGINT:程序终⽌信号。程序运⾏过程中,按Ctrl+C键将产⽣该信号。
(3)SIGQUIT:程序退出信号。程序运⾏过程中,按Ctrl+\\键将产⽣该信号。
(4)SIGBUS和SIGSEGV:进程访问⾮法地址。
(5)SIGFPE:运算中出现致命错误,如除零操作、数据溢出等。
(6)SIGKILL:⽤户终⽌进程执⾏信号。shell下执⾏kill -9发送该信号。
(7)SIGTERM:结束进程信号。shell下执⾏kill 进程pid发送该信号。
(8)SIGALRM:定时器信号。
(9)SIGCLD:⼦进程退出信号。如果其⽗进程没有忽略该信号也没有处理该信号,则⼦进程退出后将形成僵⼫进程。
信号来源
信号是软件层次上对中断机制的⼀种模拟,是⼀种异步通信⽅式,,信号可以在⽤户空间进程和内核之间直接交互,内核可以利⽤信号来通知⽤户空间的进程发⽣了哪些系统事件,信号事件主要有两个来源:
硬件来源:⽤户按键输⼊Ctrl+C退出、硬件异常如⽆效的存储访问等。
软件终⽌:终⽌进程信号、其他进程调⽤kill函数、软件异常产⽣信号。
信号⽣命周期和处理流程
(1)信号被某个进程产⽣,并设置此信号传递的对象(⼀般为对应进程的pid),然后传递给操作系统;
(2)操作系统根据接收进程的设置(是否阻塞)⽽选择性的发送给接收者,如果接收者阻塞该信号(且该信号是可以阻塞的),操作系统将暂时保留该信号,⽽不传递,直到该进程解除了对此信号的阻塞(如果对应进程已经退出,则丢弃此信号),如果对应进程没有阻塞,操作系统将传递此信号。
(3)⽬的进程接收到此信号后,将根据当前进程对此信号设置的预处理⽅式,暂时终⽌当前代码的执⾏,保护上下⽂(主要包括临时寄存器数据,当前程序位置以及当前CPU的状态)、转⽽执⾏中断服务程序,执⾏完成后在回复到中断的位置。当然,对于抢占式内核,在中断返回时还将引发新的调度。
调度。
4. 消息(Message)队列
消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符表⽰。
与管道(⽆名管道:只存在于内存中的⽂件;命名管道:存在于实际的磁盘介质或者⽂件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显⽰地删除⼀个消息队列时,该消息队列才会被真正的删除。
另外与管道不同的是,消息队列在某个进程往⼀个队列写⼊消息之前,并不需要另外某个进程在该队列上等待消息的到达。
消息队列特点总结:
(1)消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识.
(2)消息队列允许⼀个或多个进程向它写⼊与读取消息.
(3)管道和消息队列的通信数据都是先进先出的原则。
(4)消息队列可以实现消息的随机查询,消息不⼀定要以先进先出的次序读取,也可以按消息的类型读取.⽐FIFO更有优势。
(5)消息队列克服了信号承载信息量少,管道只能承载⽆格式字节流以及缓冲区⼤⼩受限等缺。
(6)⽬前主要有两种类型的消息队列:POSIX消息队列以及System V消息队列,系统V消息队列⽬前被⼤量使⽤。系统V消息队列是随内核持续的,只有在内核重起或者⼈⼯删除时,该消息队列才会被删除。
5. 共享内存(share memory)
使得多个进程可以可以直接读写同⼀块内存空间,是最快的可⽤IPC形式。是针对其他通信机制运⾏效率较低⽽设计的。
为了在多个进程间交换信息,内核专门留出了⼀块内存区,可以由需要访问的进程将其映射到⾃⼰的私有地址空间。进程就可以直接读写这⼀块内存⽽不需要进⾏数据的拷贝,从⽽⼤⼤提⾼效率。
由于多个进程共享⼀段内存,因此需要依靠某种同步机制(如信号量)来达到进程间的同步及互斥。
6. 信号量(semaphore)
信号量是⼀个计数器,⽤于多进程对共享数据的访问,信号量的意图在于进程间同步。
为了获得共享资源,进程需要执⾏下列操作:
(1)创建⼀个信号量:这要求调⽤者指定初始值,对于⼆值信号量来说,它通常是1,也可是0。
(2)等待⼀个信号量:该操作会测试这个信号量的值,如果⼩于0,就阻塞。也称为P操作。
(3)挂出⼀个信号量:该操作将信号量的值加1,也称为V操作。
为了正确地实现信号量,信号量值的测试及减1操作应当是原⼦操作。为此,信号量通常是在内核中实现的。Linux环境中,有三种类型:Posix()有名信号量(使⽤Posix IPC名字标识)、Posix基于内存的信号量(存放在共享内存区中)、System V信号量(在内核中维护)。这三种信号量都可⽤于进程间或线程间的同步。
两个进程使⽤⼀个⼆值信号量
两个进程所以⽤⼀个Posix有名⼆值信号量
⼀个进程两个线程共享基于内存的信号量
信号量与普通整型变量的区别:
(1)信号量是⾮负整型变量,除了初始化之外,它只能通过两个标准原⼦操作:wait(semap) , signal(semap) ; 来进⾏访问;
进程通信方式(2)操作也被成为PV原语(P来源于荷兰语proberen"测试",V来源于荷兰语verhogen"增加",P表⽰通过的意思,V表⽰释放的意思),⽽普通整型变量则可以在任何语句块中被访问;
信号量与互斥量之间的区别:
(1)互斥量⽤于线程的互斥,信号量⽤于线程的同步。这是互斥量和信号量的根本区别,也就是互斥和同步之间的区别。
互斥:是指某⼀资源同时只允许⼀个访问者对其进⾏访问,具有唯⼀性和排它性。但互斥⽆法限制访问者对资源的访问顺序,即访问是⽆序的。
同步:是指在互斥的基础上(⼤多数情况),通过其它机制实现访问者对资源的有序访问。
在⼤多数情况下,同步已经实现了互斥,特别是所有写⼊资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源
(2)互斥量值只能为0/1,信号量值可以为⾮负整数。
也就是说,⼀个互斥量只能⽤于⼀个资源的互斥访问,它不能实现多个资源的多线程互斥问题。信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量是,也可以完成⼀个资源的互斥访问。
(3)互斥量的加锁和解锁必须由同⼀线程分别对应使⽤,信号量可以由⼀个线程释放,另⼀个线程得到。
7. 套接字(socket)
套接字是⼀种通信机制,凭借这种机制,客户/服务器(即要进⾏通信的进程)系统的开发⼯作既可以在本地单机上进⾏,也可以跨⽹络进⾏。也就是说它可以让不在同⼀台计算机但通过⽹络连接计算机上的进程进⾏通信。
Socket是应⽤层和传输层之间的桥梁
套接字是⽀持TCP/IP的⽹络通信的基本操作单元,可以看做是不同主机之间的进程进⾏双向通信的端点,简单的说就是通信的两⽅的⼀种约定,⽤套接字中的相关函数来完成通信过程。
套接字特性
套接字的特性由3个属性确定,它们分别是:域、端⼝号、协议类型。
(1)套接字的域
它指定套接字通信中使⽤的⽹络介质,最常见的套接字域有两种:
⼀是AF_INET,它指的是Internet⽹络。当客户使⽤套接字进⾏跨⽹络的连接时,它就需要⽤到服务器计算机的IP地址和端⼝来指定⼀台联⽹机器上的某个特定服务,所以在使⽤socket作为通信的终点,服务器应⽤程序必须在开始通信之前绑定⼀个端⼝,服务器在指定的端⼝等待客户的连接。
另⼀个域AF_UNIX,表⽰UNIX⽂件系统,它就是⽂件输⼊/输出,⽽它的地址就是⽂件名。
(2)套接字的端⼝号
每⼀个基于TCP/IP⽹络通讯的程序(进程)都被赋予了唯⼀的端⼝和端⼝号,端⼝是⼀个信息缓冲区,⽤于保留Socket中的输⼊/输出信息,端⼝号是⼀个16位⽆符号整数,范围是0-65535,以区别主机上的每⼀个程序(端⼝号就像房屋中的房间号),低于256的端⼝号保留给标准应⽤程序,⽐如pop3的端⼝号就是110,每⼀个套接字都组合进了IP地址、端⼝,这样形成的整体就可以区别每⼀个套接字。
(3)套接字协议类型
因特⽹提供三种通信机制,
⼀是流套接字,流套接字在域中通过TCP/IP连接实现,同时也是AF_UNIX中常⽤的套接字类型。流套接字提供的是⼀个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,⽽且它还有⼀定的出错后重新发送的机制。
⼆个是数据报套接字,它不需要建⽴连接和维持⼀个连接,它们在域中通常是通过UDP/IP协议实现的。它对可以发送的数据的长度有限制,数据报作为⼀个单独的⽹络消息被传输,它可能会丢失、复制或错乱到达,UDP不是⼀个可靠的协议,但是它的速度⽐较⾼,因为它并⼀需要总是要建⽴和维持⼀个连接。
三是原始套接字,原始套接字允许对较低层次的协议直接访问,⽐如IP、 ICMP协议,它常⽤于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以⾃如地控制Windows下的多种协议,能够对⽹络底层的传输机制进⾏控制,所以可以应⽤原始套接字来操纵⽹络层和传输层应⽤。⽐如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以⽤来发送⼀些⾃定包头或⾃定协议的IP包。⽹络监听技术很⼤程度上依赖于SOCKET_RAW。
原始套接字与标准套接字的区别在于:
原始套接字可以读写内核没有处理的IP数据包,⽽流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。
因此,如果要访问其他协议发送数据必须使⽤原始套接字。
套接字通信的建⽴
** 服务器端**
(1)⾸先服务器应⽤程序⽤系统调⽤socket来创建⼀个套接字,它是系统分配给该服务器进程的类似⽂件描述符的资源,它不能与其他的进程共享。
(2)然后,服务器进程会给套接字起个名字,我们使⽤系统调⽤bind来给套接字命名。然后服务器进程就开始等待客户连接到这个套接字。
(3)接下来,系统调⽤listen来创建⼀个队列并将其⽤于存放来⾃客户的进⼊连接。
(4)最后,服务器通过系统调⽤accept来接受客户的连接。它会创建⼀个与原有的命名套接不同的新套接字,这个套接字只⽤于与这个特定客户端进⾏通信,⽽命名套接字(即原先的套接字)则被保留下来继续处理来⾃其他客户的连接(建⽴客户端和服务端的⽤于通信的流,进⾏通信)。
客户端
(1)客户应⽤程序⾸先调⽤socket来创建⼀个未命名的套接字,然后将服务器的命名套接字作为⼀个地址来调⽤connect与服务器建⽴连接。
(2)⼀旦连接建⽴,我们就可以像使⽤底层的⽂件描述符那样⽤套接字来实现双向数据的通信(通过流进⾏数据传输)。
三、参考引⽤

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。