chst365's blog chst365's blog
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

chst365

DIV工程师
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Git

  • 网络

  • 操作系统

    • 进程与线程
    • 进程通信
      • 进程通信
      • 进程间通信的7种方式
        • 管道/匿名管道(pipe)
        • 有名管道(FIFO)
        • 信号(Signal)
        • 消息(Message)队列
        • 共享内存(share memory)
        • 信号量(semaphore)
        • 套接字(socket)
    • 进程调度策略
    • 死锁
    • I O多路复用
  • 开发必备
  • 操作系统
chst365
2022-08-31
目录

进程通信

# 进程通信

每个进程有各自不同的地址空间,任何一个进程的全局变量在另一个进程中都看不到。 所以进程间交换数据必通过内核。 在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区吧数据读走,这种机制叫进程间通信(IPC)

# 进程间通信的7种方式

# 管道/匿名管道(pipe)

  • 管道是半双工,数据只能向一个方向流动;若双方通信,需建立两个通道。
  • 只能用于父子、兄弟进程间
  • 单独构成一种独立的文件系统 管道对于管道两端的进程而言,就是一个文件,但它不属于某种文件系统,自立门户,且只存在于内存中。
  • 数据的读出和写入 一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,且每次都从缓冲区头部读数据。

管道的实质是一个内核缓冲区。进程以先进先出的方式向缓冲区存取数据。 缓冲区可看作一个循环队列,读和写的位置都是自动增长的,不能随意改变,一个数据只能被读一次,读出后在缓冲区就不存在。 当缓冲区读空或写满时,有规则控制相应的读写进程进入等待队列,当缓冲区可操作时,就唤醒等待队列中的进程继续读写。

# 管道的局限

  • 只支持单向数据流
  • 只能用于有亲缘关系的进程间
  • 没有名字
  • 管道的缓冲区是有限的(管道只存在于内存中,创建时,为其分一个页面大小)
  • 管道所传送的是无格式字节流,这要求读写方必须事先约定好数据格式

# 有名管道(FIFO)

匿名管道,因为无名,只能用于有亲缘关系的进程间通信。有名管道提供了一个路径名与之关联。 以有名管道的文件形式存在于文件系统中,无亲缘关系的进程,只要可访问该路径,就可通信 有名管道的名字存在文件系统中,内容存在内存中

匿名/有名管道总结:

  • 管道是特殊类型文件,在先入先出下可读写,不能定位读写
  • 匿名是单向的,只在有亲缘关系的进程间通信;有名以磁盘文件的方式存在,可在本机任意两个进程通信
  • 匿名阻塞问题:它无需显示打开,创建时直接返回文件描述符,在读写时需确定对方的存在,否则将退出。写数据过大,写操作阻塞,通道无数据,读操作阻塞。
  • 有名阻塞问题:在打开是需确定对方的存在,否则阻塞。可在同一进程进行读写,不会阻塞。

# 信号(Signal)

  • 信号是Linux中用于进程间通信或操作的一种机制,可在任何时候发给某一进程,无需知道该进程的状态
  • 若进程未执行,信号在内核保存,直到进程执行时传给它
  • 若信号被进程设为阻塞,则被延迟传递,直到阻塞取消

# Linux中常用信号

  • SIGHUP 用户从终端注销,所有已启动进程都将收到该进程。系统缺省状态下对该信号的处理是终止进程
  • SIGINT 程序终止信号
  • SIGQUIT 程序退出信号
  • SIGBUS和SIGSEGV 进程访问非法地址
  • SIGFPE 运算中出现致命错误,如除零操作、数据溢出等
  • SIGKILL 用户终止进程执行信号。shell下执行kill -9发送该信号。
  • SIGTERM 结束进程信号。 shell下执行kill 进程pid发送该信号
  • SIGALRM 定时器信号
  • SIGCLD 子进程退出信号。如果其父进程没有忽略该信号也没有处理该信号,则子进程退出后将形成僵尸进程。

# 信号来源

  • 硬件来源 用户退出、硬件异常如无效的存储访问
  • 软件终止 终止进程信号、其他进程调用kill函数、软件异常产生信号 信号是软件层次对中断机制的模拟,异步通信,可在进程和内核间直接交互。内核用信号通知进程发生哪些系统事件

# 信号生命周期和处理流程

  • 信号被某进程产生,设置它传递的对象(一般为进程的pid),传给系统
  • 系统根据接收进程的设置(是否阻塞)选择性发给接收者,若接收者阻塞,则保留,不传,待解除阻塞再传,若进程已退,丢弃信号
  • 目标进程收到信号,对信号预处理,暂时终止当前代码的执行,保护上下文,执行中断服务程序,执行完后恢复中断位置。对于抢占式内核,在中断返回时还将引发新的调度

# 消息(Message)队列

  • 消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符表示。
  • 与管道(无名只存在内存中的文件,有名存在磁盘或文件系统)不同的是它存在内核中,只在内核重启(系统重启)或显示地删除消息队列时,它才会被真正删除
  • 与管道不同,它在某进程往一个队列写入信息前,并不需另一进程在队列上等待信息的到达

# 消息队列特点

  • 消息的链表,特定格式,存在内存中由消息队列标识符标识
  • 允许多个进程向它读写信息
  • 它和管道的通信数据都是先进先出
  • 它可实现消息的随机查询,消息不一定要以先进先出读,也可按消息的类型读
  • 它信号承载量多,管道只能承载无格式字节流及缓冲区大小限制
  • 它目前有两种类型:POSIX和System V,后者目前被大量使用,其随内核持续,只在内核重启或人工删除,才会被删

# 共享内存(share memory)

  • 多个进程可直接读写同一块内存空间,最快
  • 为了多进程间通信,内核专门留意内存区,由需访问的进程将其映射到自己的私有地址空间。进程可直接读写这一内存而不需进行数据的拷贝,大大提高效率
  • 由于多进程共享同一内存,因此需依靠某种同步机制(如信号量)来达到进程间的同步及互斥

# 信号量(semaphore)

信号量是一个计数器,用于多进程对共享数据的访问,目的在于进程间同步 为获取共享资源,进程需操作:

  • 创建一个信号量:调用者指定初始值,对于二值信号量来说,它通常是1,也可是0
  • 等待一个信号量:测试信号量的值,若<0,就阻塞 P操作
  • 挂出一个信号量:信号量+1 V操作

信号量值的测试和减一操作是原子操作,在内核中进行。 在Linux中,有三种:Posix(可移植性操作系统接口)有名信号量(使用Posix IPC名字标识)、Posix基于内存的信号量(存放在共享内存区中)、System V信号量(在内核中维护)。它们都快用于进程间或线程间的同步。

两进程使用一个二值信号量: 两进程使用一个二值信号量 两进程使用一个Posix有名二值信号量: 两进程使用一个Posix有名二值信号量 一进程两线程共享基于内存的信号量: 一进程两线程共享基于内存的信号量

# 信号量和普通整形变量的区别

  • 信号量是非负整形变量,除初始化外,它只能通过两个标准原子操作:wait(semap)、signal(semap)
  • 操作也被称为PV原语(P 源于荷兰语 测试,表通过,V 增加,表释放),而普通则可在任一语块中被访问

# 信号量和互斥量的区别

  • 互斥量用于线程的互斥,信号量用于线程的同步 互斥指某一资源同时只允许一个访问者对其访问,有唯一性和排它性,但访问是无序的 同步在互斥的基础上,通过其他机制实现对资源的有序访问
  • 互斥量值只能为0/1,信号量可为非负整数 一个互斥量只能用于一个资源的互斥访问,不能多个资源多线程互斥。信号量可多个资源多线程互斥和同步。当信号量为单值,也可完成一个资源的互斥访问。
  • 互斥量的加锁和解锁必须由同一线程分别使用,信号量可有一个线程释放,另一线程得到。

# 套接字(socket)

Socket是应用层和传输层之间的桥梁 套接字是一种通信机制,客户/服务器系统的开发工作既可在本地单机进行,也可跨网进行。即它可让不在同一计算机但通过网络连接计算机上进程进行通信。 它支持TCP/IP的网络通信的基本操作单元。不同主机间的进程进行双向通信,用套接字中的函数来完成通信。

# 套接字特性

  • 域 指通信中使用的网络介质
    • AF_INET 指internet网络,当客户用套接字进行跨网连接时,它需用到服务器计算机的IP和端口来指定一台联网机器上的某个特定服务,所以在使用它作为通信的终点,服务器应用程序必须在通信前绑定一端口,服务器在指定端口等待客户的连接
    • AF_UNIX 指UNIX文件系统,它就是文件输入/输出,它的地址是文件名
  • 端口号 每一个基于TCP/IP网络通讯的程序(进程)都被赋予唯一的端口和端口号,端口是一个信息缓冲区,用于保留Socket中的输入/输出信息,端口号是一个16位无符号整数,范围是0-65535,以区别主机上的每一个程序(端口号就像房屋中的房间号),低于256的端口号保留给标准应用程序,比如pop3的端口号就是110,每一个套接字都组合进了IP地址、端口,这样形成的整体就可以区别每一个套接字。
  • 协议类型 因特网提供三种通信机制:
    • 流套接字 在域中通过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协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。

# 套接字通信的建立

Socket通信基本流程:

服务端

  • 首先服务器应用程序用系统调用socket来创建一个套接字,它是系统分配给该服务器进程的类似文件描述符的资源,它不能与其他的进程共享。
  • 服务器进程会给套接字起个名字,我们使用系统调用bind来给套接字命名。然后服务器进程就开始等待客户连接到这个套接字。
  • 系统调用listen来创建一个队列并将其用于存放来自客户的进入连接
  • 服务器通过系统调用accept来接受客户的连接。它会创建一个与原有的命名套接不同的新套接字,这个套接字只用于与这个特定客户端进行通信,而命名套接字(即原先的套接字)则被保留下来继续处理来自其他客户的连接(建立客户端和服务端的用于通信的流,进行通信)

客户端

  • 客户应用程序首先调用socket来创建一个未命名的套接字,然后将服务器的命名套接字作为一个地址来调用connect与服务器建立连接
  • 一旦连接建立,我们就可以像使用底层的文件描述符那样用套接字来实现双向数据的通信(通过流进行数据传输)
#开发必备#操作系统
上次更新: 2022/11/29, 15:43:28
进程与线程
进程调度策略

← 进程与线程 进程调度策略→

最近更新
01
面试官
03-27
02
this&指针&作用域&闭包
03-27
03
前端
03-27
更多文章>
Theme by Vdoing | Copyright © 2019-2025 chst365 | 豫ICP备17031889号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式