进程间通讯的7种⽅式
1、常见的通信⽅式
1. 管道pipe:管道是⼀种半双⼯的通信⽅式,数据只能单向流动,⽽且只能在具有亲缘关系的进程间使⽤。进程的亲缘关系通常是指⽗
⼦进程关系。
2. 命名管道FIFO:有名管道也是半双⼯的通信⽅式,但是它允许⽆亲缘关系进程间的通信。
3. 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管
道只能承载⽆格式字节流以及缓冲区⼤⼩受限等缺点。
4. 共享存储SharedMemory:共享内存就是映射⼀段能被其他进程所访问的内存,这段共享内存由⼀个进程创建,但多个进程都可以访
问。共享内存是最快的 IPC ⽅式,它是针对其他进程间通信⽅式运⾏效率低⽽专门设计的。它往往与其他通信机制,如信号量,配合使⽤,来实现进程间的同步和通信。
5. 信号量Semaphore:信号量是⼀个计数器,可以⽤来控制多个进程对共享资源的访问。它常作为⼀种锁机制,防⽌某进程正在访问共
享资源时,其他进程也访问该资源。因此,主要作为进程间以及同⼀进程内不同线程之间的同步⼿段。
6. 套接字Socket:套解⼝也是⼀种进程间通信机制,与其他通信机制不同的是,它可⽤于不同及其间的进程通信。
7. 信号 ( sinal ) : 信号是⼀种⽐较复杂的通信⽅式,⽤于通知接收进程某个事件已经发⽣。
2、按通信类型区分
1. 共享存储器系统
1.基于共享数据结构的通信⽅式
(仅适⽤于传递相对少量的数据,通信效率低,属于低级通信)
2.基于共享存储区的通信⽅式
2. 管道通信系统
管道是指⽤于连接⼀个读进程和⼀个写进程以实现它们之间通信的⼀个共享⽂件(pipe⽂件)
管道机制需要提供⼀下⼏点的协调能⼒
1.互斥,即当⼀个进程正在对pipe执⾏读/写操作时,其它进程必须等待
2.同步,当⼀个进程将⼀定数量的数据写⼊,然后就去睡眠等待,直到读进程将数据取⾛,再去唤醒。读进程与之类似
3.确定对⽅是否存在
3. 消息传递系统
1.直接通信⽅式
发送进程利⽤OS所提供的发送原语直接把消息发给⽬标进程
2.间接通信⽅式
发送和接收进程都通过共享实体(邮箱)的⽅式进⾏消息的发送和接收
4. 客户机服务器系统
1.套接字 – 通信标识型的数据结构是进程通信和⽹络通信的基本构件
基于⽂件型的 (当通信进程都在同⼀台服务器中)其原理类似于管道
基于⽹络型的(⾮对称⽅式通信,发送者需要提供接收者命名。通信双⽅的进程运⾏在不同主机环境下被分配了⼀对套接字,⼀个属于发送进程,⼀个属于接收进程)
2.远程过程调⽤和远程⽅法调⽤
3、详解
3.1 管道
管道,通常指⽆名管道,是 UNIX 系统IPC最古⽼的形式。
1、特点:
它是半双⼯的(即数据只能在⼀个⽅向上流动),具有固定的读端和写端。
它只能⽤于具有亲缘关系的进程之间的通信(也是⽗⼦进程或者兄弟进程之间)。
它可以看成是⼀种特殊的⽂件,对于它的读写也可以使⽤普通的read、write 等函数。但是它不是普通的⽂件,并不属于其他任何⽂件系统,并且只存在于内存中。
管道分为pipe(⽆名管道)和fifo(命名管道)两种,除了建⽴、打开、删除的⽅式不同外,这两种管道⼏乎是⼀样的。他们都是通过内核缓冲区实现数据传输。
pipe⽤于相关进程之间的通信,例如⽗进程和⼦进程,它通过pipe()系统调⽤来创建并打开,当最后⼀个使⽤它的进程关闭对他的引⽤时,pipe将⾃动撤销。
FIFO即命名管道,在磁盘上有对应的节点,但没有数据块——换⾔之,只是拥有⼀个名字和相应的访问权限,通过mknode()系统调⽤或者mkfifo()函数来建⽴的。⼀旦建⽴,任何进程都可以通过⽂件名将其打开和进⾏读写,⽽不局限于⽗⼦进程,当然前提是进程对FIFO有适当的访问权。当不再被进程使⽤时,FIFO在内存中释放,但磁盘节点仍然存在。
管道的实质是⼀个内核缓冲区,进程以先进先出的⽅式从缓冲区存取数据:管道⼀端的进程顺序地将进程数据写⼊缓冲区,另⼀端的进程则顺序地读取数据,该缓冲区可以看做⼀个循环队列,读和写的位置都是⾃动增加的,⼀个数据只能被读⼀次,读出以后再缓冲区都不复存在了。当缓冲区读空或者写满时,有⼀定的规则控制相应的读进程或写进程是否进⼊等待队列,当空的缓冲区有新数据写⼊或慢的缓冲区有数据读出时,就唤醒等待队列中的进程继续读写。
3.2 ⽆名管道
pipe的例⼦:⽗进程创建管道,并在管道中写⼊数据,⽽⼦进程从管道读出数据
3.3 命名管道
和⽆名管道的主要区别在于,命名管道有⼀个名字,命名管道的名字对应于⼀个磁盘索引节点,有了这个⽂件名,任何进程有相应的权限都可以对它进⾏访问。
⽽⽆名管道却不同,进程只能访问⾃⼰或祖先创建的管道,⽽不能访任意访问已经存在的管道——因为没有名字。
Linux中通过系统调⽤mknod()或makefifo()来创建⼀个命名管道。最简单的⽅式是通过直接使⽤shell
mkfifo myfifo
等价于
mknod myfifo p
以上命令在当前⽬录下创建了⼀个名为myfifo的命名管道。⽤ls -p命令查看⽂件的类型时,可以看到命名管道对应的⽂件名后有⼀条竖线"|",表⽰该⽂件不是普通⽂件⽽是命名管道。
使⽤open()函数通过⽂件名可以打开已经创建的命名管道,⽽⽆名管道不能由open来打开。当⼀个命名管道不再被任何进程打开时,它没有消失,还可以再次被打开,就像打开⼀个磁盘⽂件⼀样。
可以⽤删除普通⽂件的⽅法将其删除,实际删除的事磁盘上对应的节点信息。
进程通信方式例⼦:⽤命名管道实现聊天程序,⼀个张三端,⼀个李四端。两个程序都建⽴两个命名管道,fifo1,fifo2,张三写fifo1,李四读fifo1;李四写fifo2,张三读fifo2。
⽤select把,管道描述符和stdin假如集合,⽤select进⾏阻塞,如果有i/o的时候唤醒进程。(粉红⾊部分为select部分,黄⾊部分为命名管道部分)
3.4 消息队列
消息队列,就是⼀个消息的链表,是⼀系列保存在内核中消息的列表。⽤户进程可以向消息队列添加消息,也可以向消息队列读取消息。
消息队列与管道通信相⽐,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,⽽是可以根据⾃定义条件接收特定类型的消息。
可以把消息看做⼀个记录,具有特定的格式以及特定的优先级。对消息队列有写权限的进程可以向消息队列中按照⼀定的规则添加新消息,对消息队列有读权限的进程可以从消息队列中读取消息。
消息队列的常⽤函数如下表:
进程间通过消息队列通信,主要是:创建或打开消息队列,添加消息,读取消息和控制消息队列。
3.5 共享内存
共享内存允许两个或多个进程共享⼀个给定的存储区,这⼀段存储区可以被两个或两个以上的进程映射⾄⾃⾝的地址空间中,⼀个进程写⼊共享内存的信息,可以被其他使⽤这个共享内存的进程,通过⼀个简单的内存读取错做读出,从⽽实现了进程间的通信。
采⽤共享内存进⾏通信的⼀个主要好处是效率⾼,因为进程可以直接读写内存,⽽不需要任何数据的拷贝,对于像管道和消息队⾥等通信⽅式,则需要再内核和⽤户空间进⾏四次的数据拷贝,⽽共享内存则只拷贝两次:⼀次从输⼊⽂件到共享内存区,另⼀次从共享内存到输出⽂件。
⼀般⽽⾔,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时在重新建⽴共享内存区域;⽽是保持共享区域,直到通信完毕为⽌,这样,数据内容⼀直保存在共享内存中,并没有写回⽂件。共享内存中的内容往往是在解除映射时才写回⽂件,因此,采⽤共享内存的通信⽅式效率⾮常⾼。
共享内存有两种实现⽅式:1、内存映射 2、共享内存机制
3.6 信号量
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是⼀个计数器。信号量⽤于实现进程间的互斥与同步,⽽不是⽤于存储进程间通信数据。
1、特点
信号量⽤于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原⼦操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,⽽且可以加减任意正整数。
⽀持信号量组。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论