操作系统--进程通信方式

管道

一种单项传输数据的东西
管道这种通信方式效率低,不适合进程间频繁地交换数据。
没有名字的叫匿名管道 比如
$ ps auxf | grep mysql
中间的竖线就是管道
这条指令是将前半段的输出作为后半段的输入

管道还有另外一个类型是命名管道,也被叫做 FIFO,因为数据是先进先出的传输方式。
参考连接:https://xiaolincoding.com/os/4_process/process_commu.html#%E6%80%BB%E7%BB%93

管道如何创建

int pipe(int fd[2]

通过以上系统调用创建,表示创建一个匿名管道,并返回两个描述符,一个是管道的读取端描述符 fd[0],另一个是管道的写入端描述符 fd[1],匿名管道是特殊的文件,只存在于内存,不存于文件系统中。管道就是内核里的一个缓存

在这里插入图片描述
对于匿名管道,它的通信范围是存在父子关系的进程。
对于命名管道,它可以在不相关的进程间也能相互通信

消息队列

管道通信效率低 不适合进程间频繁交换数据
对此,消息队列的通信模式可以解决,消息队列是保存在内核中的一个消息链表,在发送数据时,会分成一个个独立的数据单元,也就是消息体(数据块)。A进程要给B进程发消息时,只需要把数据放在对应消息队列,B进程需要的时候再去读取。
但消息队列也有不足的点:1.通信不及时 2.附件大小有限制
3.消息队列通信过程中,存在用户态和内核态之间数据拷贝的开销 因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

共享内存

共享内存可以解决内核态和用户态之间消息拷贝的开销
**共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。**所有进程都能看到这块物理内存
在这里插入图片描述

信号量

使用共享内存方式有一个问题,如果多个线程同时修改共享内存里的同一个东西,会造成冲突,此时可以使用信号量来防止这种情况产生。(信号量是实现进程间同步和互斥的,不是一种通信方式

信号量表示资源数量,控制信号量的方式有两种原子操作:
一个是 P 操作,这个操作会把信号量减去 1,相减后如果信号量 < 0,则表明资源已被占用,进程需阻塞等待;相减后如果信号量 >= 0,则表明还有资源可使用,进程可正常继续执行。
另一个是 V 操作,这个操作会把信号量加上 1,相加后如果信号量 <= 0,则表明当前有阻塞中的进程,于是会将该进程唤醒运行;相加后如果信号量 > 0,则表明当前没有阻塞中的进程;

详细看:https://xiaolincoding.com/os/4_process/process_commu.html#%E4%BF%A1%E5%8F%B7%E9%87%8F

信号量初始化1 是互斥信号量,保证共享内存中任何时刻只有一个进程访问,先P后V,如图:
在这里插入图片描述
信号量初始化为0,是同步信号量,保证进程顺序执行,保证进程A在进程B之前执行
进程B P时会被阻塞,在A V完后会唤醒B
在这里插入图片描述

信号

对于异常状态下,需要用信号的方式来通知进程
在 Linux 操作系统中, 为了响应各种各样的事件,提供了几十种信号,分别代表不同的意义。我们可以通过 kill -l 命令,查看所有的信号
运行在 shell 终端的进程,我们可以通过键盘输入某些组合键的时候,给进程发送信号。例如

Ctrl+C 产生 SIGINT 信号,表示终止该进程;
Ctrl+Z 产生 SIGTSTP 信号,表示停止该进程,但还未结束;

信号是进程间通信机制中唯一的异步通信机制,因为可以在任何时候发送信号给某一进程,一旦有信号产生,我们就有下面这几种,用户进程对信号的处理方式。
1.执行默认操作。Linux 对每种信号都规定了默认操作,例如,上面列表中的 SIGTERM 信号,就是终止进程的意思。

2.捕捉信号。我们可以为信号定义一个信号处理函数。当信号发生时,我们就执行相应的信号处理函数。

3.忽略信号。当我们不希望处理某些信号的时候,就可以忽略该信号,不做任何处理。有两个信号是应用进程无法捕捉和忽略的,即 SIGKILL 和 SEGSTOP,它们用于在任何时候中断或结束某一进程。

Socket

跨网络进行不同主机间通信,就需要socket通信(socket也可以同主机进程间通信)
socket系统调用:

int socket(int domain,int type,int protocal)

domain 参数用来指定协议族,比如 AF_INET 用于 IPV4、AF_INET6 用于 IPV6、AF_LOCAL/AF_UNIX 用于本机;
type 参数用来指定通信特性,比如 SOCK_STREAM 表示的是字节流,对应 TCP、SOCK_DGRAM 表示的是数据报,对应 UDP、SOCK_RAW 表示的是原始套接字;
protocal 参数原本是用来指定通信协议的,但现在基本废弃。因为协议已经通过前面两个参数指定完成,protocol 目前一般写成 0 即可;
根据创建 socket 类型的不同,通信的方式也就不同:

实现 TCP 字节流通信: socket 类型是 AF_INET 和 SOCK_STREAM;
实现 UDP 数据报通信:socket 类型是 AF_INET 和 SOCK_DGRAM;
实现本地进程间通信: 「本地字节流 socket 」类型是 AF_LOCAL 和 SOCK_STREAM,「本地数据报 socket 」类型是 AF_LOCAL 和 SOCK_DGRAM。另外,AF_UNIX 和 AF_LOCAL 是等价的,所以 AF_UNIX 也属于本地 socket;
TCP:
在这里插入图片描述
服务端和客户端初始化 socket,得到文件描述符;
服务端调用 bind,将绑定在 IP 地址和端口;
服务端调用 listen,进行监听;
服务端调用 accept,等待客户端连接;
客户端调用 connect,向服务器端的地址和端口发起连接请求;
服务端 accept 返回用于传输的 socket 的文件描述符;
客户端调用 write 写入数据;服务端调用 read 读取数据;
客户端断开连接时,会调用 close,那么服务端 read 读取数据的时候,就会读取到了 EOF,待处理完数据后,服务端调用 close,表示连接关闭。
这里需要注意的是,服务端调用 accept 时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据。

所以,监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket。

成功连接建立之后,双方开始通过 read 和 write 函数来读写数据,就像往一个文件流里面写东西一样。

UDP:

在这里插入图片描述
具体看:https://xiaolincoding.com/os/4_process/process_commu.html#%E6%80%BB%E7%BB%93
参考连接:https://xiaolincoding.com/os/4_process/process_commu.html#%E6%80%BB%E7%BB%93

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值