进程间的通信方式

https://blog.youkuaiyun.com/jmy5945hh/article/details/7350564

这个太多了,没整理完
https://blog.youkuaiyun.com/wh_sjc/article/details/70283843#commentBox

进程是一个程序的一次执行过程。进程用户空间是相互独立的,一般而言是不能相互访问的。 但很多情况下进程间需要互相通信,来完成系统的某项功能。进程通过与内核及其它进程之间的互相通信来协调它们的行为。

多进程:
首先,先来讲一下fork之后,发生了什么事情。

由fork创建的新进程被称为子进程(child process)。该函数被调用一次,但返回两次。两次返回的区别是子进程的返回值是0,而父进程的返回值则是新进程(子进程)的进程 id。将子进程id返回给父进程的理由是:因为一个进程的子进程可以多于一个,没有一个函数使一个进程可以获得其所有子进程的进程id。对子进程来说,之所以fork返回0给它,是因为它随时可以调用getpid()来获取自己的pid;也可以调用getppid()来获取父进程的id。(进程id 0总是由交换进程使用,所以一个子进程的进程id不可能为0 )。

fork之后,操作系统会复制一个与父进程完全相同的子进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完整拷贝,指令指针也完全相同,子进程拥有父进程当前运行到的位置(两进程的程序计数器pc值相同,也就是说,子进程是从fork返回处开始执行的),但有一点不同,如果fork成功,子进程中fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。可以这样想象,2个进程一直同时运行,而且步调一致,在fork之后,他们分别作不同的工作,也就是分岔了。这也是fork为什么叫fork的原因。

至于那一个最先运行,可能与操作系统(调度算法)有关,而且这个问题在实际应用中并不重要,如果需要父子进程协同,可以通过原语的办法解决。

进程通信的应用场景

  • 数据传输一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。

  • 共享数据多个进程想要操作共享数据一个进程对共享数据的修改,别的进程应该立刻看到

  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

  • 资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制

  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

六种通信方式

1、管道:管道只能承载无格式字节流以及缓冲区大小受限。管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道。不需要额外同步机制。

  • 无名管道:可用于具有亲缘关系(父子进程、或者拥有相同祖先的两个子进程之间)进程间的通信。无名管道是基于fork机制产生的
  • 有名管道FIFO:允许无亲缘关系进程间的通信

2、信号(Signal):信号是比较复杂的通信方式,用于通知接收进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身

  • 信号可以在任何时候发给某一进程而无需知道该进程的状态

  • 如果该进程处于未执行状态,则该信号就有内核保存起来,直到该进程恢复执行并传递给它为止。

  • 如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时信号才被传递给进程。

3、消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少管道只能承载无格式字节流以及缓冲区大小受限等缺点

消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。可以把消息看做一个记录,具有特定的格式以及特定的优先级

4、共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式,需要额外的同步机制。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,信号量结合使用,来达到进程间的同步及互斥。容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题

5、信号量(semaphore):主要作为进程间以及同一进程不同线程之间同步手段。信号量是一个计数器可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。不能传递复杂消息,只能用来同步

6、套接口(Socket):可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。

管道原理

无名管道的介绍

管道是由内核管理的一个缓冲区,相当于我们放入内存中的一个纸条。管道的一端连接一个进程的输出。这个进程会向管道中放入信息。管道的另一端连接一个进程的输入,这个进程取出被放入管道的信息。一个缓冲区不需要很大,它被设计成为环形的数据结构,以便管道可以被循环利用。

当管道中没有信息的话,从管道中读取的进程会等待,直到另一端的进程放入信息。当管道被放满信息的时候,尝试放入信息的进程会等待,直到另一端的进程取出信息。当两个进程都终结的时候,管道也自动消失。
在这里插入图片描述

无名管道如何创建

从原理上,管道利用fork机制建立从而让两个进程可以连接到同一个PIPE上。最开始的时候,上面的两个箭头都连接在同一个进程Process 1上(连接在Process 1上的两个箭头)。当fork复制进程的时候,会将这两个连接也复制到新的进程(Process 2)。随后,每个进程关闭自己不需要的一个连接 (两个黑色的箭头被关闭; Process 1关闭从PIPE来的输入连接,Process 2关闭输出到PIPE的连接),这样,剩下的红色连接就构成了如上图的PIPE。
在这里插入图片描述

无名管道创建后其对应的数据结构

在 Linux 中,管道的实现并没有使用专门的数据结构,而是借助了文件系统的file结构和VFS的索引节点inode。通过将两个 file 结构指向同一个临时的 VFS 索引节点inode,而 VFS inode 索引节点又指向一个物理页面而实现的。如下图:
在这里插入图片描述有两个 file 数据结构,但它们定义文件操作进程地址是不同的,其中一个是向管道中写入数据的例程地址,而另一个是从管道中读出数据的例程地址。这样,用户程序的系统调用仍然是通常的文件操作,而内核却利用这种抽象机制实现了管道这一特殊操作。

有名管道 FIFO (First in, First out)

实现原理

FIFO 为一种特殊的文件类型,它在文件系统中有对应的路径。当一个进程以读®的方式打开该文件,而另一个进程以写(w)的方式打开该文件,那么内核就会在这两个进程之间建立管道,所以FIFO实际上也由内核管理,不与硬盘打交道。之所以叫FIFO,是因为管道本质上是一个先进先出的队列数据结构,最早放入的数据被最先读出来,从而保证信息交流的顺序写模式的进程向FIFO文件中写入,而读模式的进程从FIFO文件中读出。 当删除FIFO文件时,管道连接也随之消失。 FIFO的 好处 在于我们可以 通过文件的路径来识别管道从而让没有亲缘关系的进程之间建立连接

套接字特性

套接字的特性由3个属性确定,它们分别是:域、端口号、协议类型

1、套接字的域
它指定套接字通信中使用的网络介质,最常见的套接字域有两种

  • 一是AF_INET,指的是Internet网络。当客户使用套接字进行跨网络的连接时,它就需要用到服务器计算机的IP地址端口来指定一台联网机器上的某个特定服务,所以在使用socket作为通信的终点,服务器应用程序必须在开始通信之前绑定一个端口,服务器在指定的端口等待客户的连接

  • 另一个域AF_UNIX(AF_LOCAL),表示UNIX文件系统,它就是文件输入/输出,而它的地址就是文件名

2、套接字的端口号
每一个基于TCP/IP网络通讯的程序(进程)都被赋予了唯一的端口和端口号端口是一个信息缓冲区,用于保留Socket中的输入/输出信息,端口号是一个16位无符号整数,范围是0-65535,以区别主机上的每一个程序(端口号就像房屋中的房间号),低于256的端口号保留给标准应用程序,比如pop3的端口号就是110,每一个套接字都组合进了IP地址、端口,这样形成的整体就可以区别每一个套接字。

3、套接字协议类型(3种)

(1)流套接字(SOCK_STREAM)
流套接字在域中通过TCP/IP连接实现,同时也是AF_UNIX中常用的套接字类型。流套接字提供的是一个有序、可靠、双向字节流的连接,因此发送的数据可以确保不会丢失、重复或乱序到达,而且它还有一定的出错后重新发送的机制。

(2)数据报套接字(SOCK_DGRAM)
它们在域中通常是通过UDP/IP协议实现的, 不需要建立连接和维持一个连接。它对可以发送的数据的长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失、重复或错乱到达,UDP不是一个可靠的协议,但是它的速度比较高

(3)原始套接字(SOCK_RAW)
原始套接字允许对较低层次的协议直接访问,比如IP、 ICMP协议,它常用于检验新的协议实现,或者访问现有服务中配置的新设备,因为RAW SOCKET可以自如地控制Windows下的多种协议,能够对网络底层的传输机制进行控制,所以可以应用原始套接字来操纵网络层和传输层应用。比如,我们可以通过RAW SOCKET来接收发向本机的ICMP、IGMP协议包,或者接收TCP/IP栈不能够处理的IP包,也可以用来发送一些自定包头或自定协议的IP包。网络监听技术很大程度上依赖于SOCKET_RAW。

原始套接字与标准套接字的区别在于:
原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据因此,如果要访问其他协议发送数据必须使用原始套接字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值