五大网络IO模型

782 阅读14分钟

网络IO模型

1. IO是什么?

I/O(英语:Input/Output),即输入/输出,通常指数据存储器(内部和外部)或其他周边设备之间的输入和输出,是信息处理系统(例如电脑)与外部世界(可能是人类或另一信息处理系统)之间的通信。

输入是系统接收的信号或数据,输出则是从其发送的信号或数据。该术语也可以用作行动的一部分;到“执行I/O”是执行输入或输出的操作。

输入/出设备是硬件中由人(或其他系统)使用与电脑进行通信的部件。例如,键盘或鼠标是电脑的输入设备,而监控器和打印机是输出设备。电脑之间的通信设备(如电信调制解调器和网卡)通常执行输入和输出操作。

将设备指定为输入或输出取决于视角。鼠标和键盘截取人类用户的肢体动作,并将其转换为电脑可解的输入信号;这些设备的输出是电脑的输入。同样,打印机和监控器则用于将电脑处理的过程和结果输出,并将这些信号转换为人类用户能理解的呈现。从用户的角度来看,阅读或查看这些呈现的过程则是接受输入;人机交互主要是在研究了解机器与人类之间这种过程的交互接口。

在现代电脑体系结构中 CPU 可以使用单独的指令直接读取或写入,被认为是电脑的核心。而 CPU 和主存储器的组合,任何信息传入或传出 CPU /内存组合,例如通过从磁盘驱动器读取数据,就会被认为是 I/O;CPU 及其电路版提供用于低端编程的存储器映射 I/O,例如在设备驱动程序的实现中,或者提供对 I/O 通道的访问。一个 I/O 算法设计是利用内存,而且高效地进行与辅助存储设备交换数据时,如一个磁盘驱动器。

2. socket是什么?

网络套接字(英语:Network socket;又译网络套接字网络接口网络插槽)在计算机科学中是电脑网络中进程间资料流的端点。使用以网际协议(Internet Protocol)为通信基础的网络套接字,称为网际套接字(Internet socket)。因为网际协议的流行,现代绝大多数的网络套接字,都是属于网际套接字。

5.25.socket2.webp

一次完整的网络通信会经过多层的传输,需要经过物理传输层的网线和网卡,网络传输层的IP协议,经过这两层之后网络数据通过Ip地址可以知道传输到那台计算机了,传输到目标计算机后,操作系统内核通过网卡读取网络数据,将网络数据存储在内存中。计算机中会运行不同的网络程序,他们可能对应于系统中的不同进程,那要如何把网卡中的网络数据识别出来是给哪个进程的,要如何持续和稳定地给到对应的应用进程呢?我想这也就是socket设计的目的和想要解决的问题了,提供一些API接口来实现应用层通过操作系统内核读取网卡数据,并且将网络数据正确地分发到对应的应用层程序。

5.25.socket.jpeg

3. 名词解释

3.1. 同步与异步(线程间调用)

 同步与异步是对应于调用者与被调用者,它们是线程之间的关系,两个线程之间要么是同步的,要么是异步的
 ​
     同步操作时,调用者需要等待被调用者返回结果,才会进行下一步操作
 ​
     而异步则相反,调用者不需要等待被调用者返回调用,即可进行下一步操作,被调用者通常依靠事件、回调等机制来通知调用者结果

3.2.阻塞与非阻塞(线程内调用)

 阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞
 ​
 阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态:
 ​
     阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
 ​
     非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。

4. 阻塞式IO模型

阻塞式I/O(Input/Output)模型是一种传统的I/O处理模型,它在进行I/O操作时会阻塞程序的执行,直到I/O操作完成才会继续执行后续的代码。在阻塞式I/O模型中,当一个I/O操作发起时,程序会一直等待,直到数据从I/O设备读取完毕或数据成功写入到I/O设备。

在阻塞式I/O模型中,当程序发起一个I/O请求,操作系统会将程序阻塞,并将控制权交给内核去处理I/O操作。当I/O操作完成后,内核会通知程序,并将控制权返回给程序继续执行后续的代码。这种模型下,程序在等待I/O操作完成期间是无法做其他的事情的,因为它被阻塞住了。

阻塞式I/O模型的一个主要缺点是,当一个I/O操作阻塞时,整个程序都会停止响应,无法同时处理其他的任务或请求。这在需要同时处理多个并发请求的情况下会导致性能瓶颈。如果一个I/O操作非常耗时,那么其他的请求将会被阻塞,程序的整体性能也会下降。

525.1.png

5. 非阻塞式IO模型

非阻塞式I/O(Input/Output)模型是一种改进的I/O处理模型,它在进行I/O操作时不会阻塞程序的执行,而是立即返回并允许程序继续执行后续的代码。在非阻塞式I/O模型中,当程序发起一个I/O请求后,它可以继续执行其他任务而无需等待I/O操作完成。

在非阻塞式I/O模型中,当程序发起一个非阻塞的I/O请求,操作系统会立即返回一个结果,表示该I/O操作是否完成。如果操作完成,程序可以获取到相应的数据;如果操作未完成,则可以继续执行其他任务或轮询该I/O操作的状态,以确定何时完成。

非阻塞式I/O模型通常与循环轮询结合使用。程序会不断地查询(轮询)I/O操作的状态,直到操作完成为止。这种轮询的方式可以通过使用非阻塞I/O操作和辅助函数(如selectpollepoll等)来实现。

非阻塞式I/O模型的优点是可以在等待I/O操作完成的同时,继续处理其他任务,提高了程序的并发性和性能。然而,由于需要不断轮询I/O操作的状态,这可能会导致CPU资源的浪费。

需要注意的是,非阻塞式I/O模型仍然是同步I/O操作,因为程序需要主动轮询以确定I/O操作是否完成。与之相对的是异步I/O模型,异步I/O模型中的I/O操作完成后会通过回调或事件通知的方式来通知程序,而无需程序主动轮询。

=

525.2.png

6. IO多路复用

I/O多路复用(I/O Multiplexing)是一种高效的I/O处理模型,用于同时监控多个I/O操作的状态并进行处理。它可以在一个线程中同时管理多个I/O通道,而无需为每个通道创建一个独立的线程。

在I/O多路复用模型中,通过使用特定的系统调用(如selectpollepoll等)来监听多个I/O通道的事件。这些系统调用可以监视多个文件描述符(sockets、pipes等)上的读写事件,并在有事件发生时通知程序进行相应的处理。

I/O多路复用模型的基本思想是将多个I/O操作合并为一个I/O操作,然后通过系统调用进行等待,以避免阻塞线程。当任何一个I/O通道有数据可读或可写时,系统会通知程序进行相应的读取或写入操作。

使用I/O多路复用模型的主要优点是可以在单个线程中同时处理多个I/O通道,从而提高了系统的并发性能。相对于阻塞式I/O或非阻塞式I/O模型,它减少了线程的创建和上下文切换的开销。

常见的I/O多路复用系统调用有:

  1. select:在一组文件描述符上进行I/O事件的等待,支持的文件描述符数量有限。
  2. poll:与select类似,但没有文件描述符数量的限制。
  3. epoll:在Linux系统上提供的可扩展I/O事件通知机制,支持更高的并发连接数,并且效率较高。

使用I/O多路复用模型时,程序通常需要配合非阻塞式I/O操作,以避免单个I/O操作的阻塞影响其他操作。同时,需要注意合理设置I/O通道的读写缓冲区,以避免数据拷贝带来的性能损耗。

总之,I/O多路复用模型是一种高效的I/O处理模型,适用于需要同时处理多个I/O通道的场景,提高了系统的并发性能和可扩展性。

525.3.png

7. 信号驱动IO

信号驱动I/O(Signal-driven I/O)是一种I/O处理模型,通过使用信号来通知程序当一个I/O操作已经完成或有数据可读取。与传统的阻塞式I/O或非阻塞式I/O模型不同,信号驱动I/O模型允许程序在进行I/O操作时继续执行其他任务,而无需等待或轮询。

在信号驱动I/O模型中,程序首先通过系统调用(如sigaction)来注册一个信号处理函数,用于处理与I/O操作相关的信号。然后,程序发起一个异步的I/O操作,并继续执行其他任务。当I/O操作完成时,操作系统会发送一个信号(如SIGIO)给程序,程序在信号处理函数中得以知晓该I/O操作已经完成,然后可以进行数据读取或相应的处理操作。

信号驱动I/O模型的优点是可以异步地进行I/O操作,而无需阻塞程序或进行轮询,从而提高了程序的并发性能和响应性。它在某些情况下可以替代多线程或多进程模型,减少了上下文切换和线程/进程创建的开销。

需要注意的是,信号驱动I/O模型对于支持信号驱动的I/O设备和操作系统的支持是必要的。不是所有的I/O设备和操作系统都能完全支持信号驱动I/O模型。在实际应用中,需要仔细考虑和评估使用信号驱动I/O模型的可行性和适用性。

总结而言,信号驱动I/O模型通过使用信号来通知程序I/O操作的完成,允许程序在进行I/O操作时继续执行其他任务,提高了并发性能和响应性。然而,其适用性受到设备和操作系统的限制。

Snipaste_2023-05-25_16-27-51.png

8. 异步IO模型

异步I/O(Asynchronous I/O)模型是一种高级的I/O处理模型,与阻塞式I/O、非阻塞式I/O和信号驱动I/O模型有所不同。在异步I/O模型中,当一个I/O操作发起后,程序可以继续执行其他任务而无需等待该I/O操作完成。当I/O操作完成时,程序会得到通知,并可以处理已完成的操作。

在异步I/O模型中,程序发起一个异步的I/O请求,并指定一个回调函数或事件处理程序。然后,程序可以继续执行其他任务,而无需等待I/O操作完成。当I/O操作完成时,操作系统会通知程序,并调用预先指定的回调函数来处理已完成的操作。通过回调函数,程序可以获取到操作的结果或数据,并进行相应的处理。

异步I/O模型的优点是可以实现真正的并发操作,不需要主动轮询或阻塞线程等待I/O操作完成。相对于其他模型,它可以更高效地处理大量的并发I/O操作,提高系统的吞吐量和性能。

在实际应用中,异步I/O模型通常需要使用特定的异步I/O机制或库来实现,例如Windows系统上的IOCP(Input/Output Completion Ports)和Unix-like系统上的AIO(Asynchronous I/O)。这些机制提供了异步I/O操作的支持,并管理I/O操作的状态、回调处理和资源管理等。

需要注意的是,异步I/O模型的编程模式相对于其他模型更加复杂,需要合理设计和管理回调函数、事件处理程序以及可能的并发访问。但在需要处理大量并发I/O操作或具有高性能要求的应用中,异步I/O模型可以是一种有效的选择。

总结而言,异步I/O模型允许程序在发起I/O操作后继续执行其他任务,并通过回调函数或事件处理程序来处理已完成的操作。它可以实现真正的并发操作,提高系统的并发性能和吞吐量。然而,相对于其他模型,它的编程模式更加复杂。

=

525.5.png

9. 模型对比

下面是阻塞式I/O、非阻塞式I/O、I/O多路复用、信号驱动I/O和异步I/O这五个I/O模型的对比:

阻塞式I/O:

  • 当一个I/O操作发起时,程序会阻塞等待操作完成。
  • 阻塞式I/O是传统的I/O模型,适用于简单的应用场景。
  • 当有多个并发请求时,性能较差,因为每个请求都需要等待I/O操作完成。

非阻塞式I/O:

  • 当一个I/O操作发起后,程序可以继续执行其他任务,而无需等待操作完成。
  • 需要通过轮询或者选择性地进行非阻塞I/O操作的状态查询。
  • 提高了并发性能,但仍然需要不断轮询I/O操作的状态。

I/O多路复用:

  • 通过系统调用(如selectpollepoll)在多个I/O通道上监听事件。
  • 可以同时处理多个I/O通道,避免了阻塞和轮询的开销。
  • 提高了并发性能和响应性,适用于大量并发连接的场景。

信号驱动I/O:

  • 使用信号来通知程序I/O操作的完成或数据的可读取。
  • 可以异步进行I/O操作,不需要阻塞或轮询。
  • 提高了并发性能和响应性,但需要设备和操作系统的支持。

异步I/O:

  • 发起异步I/O请求后,程序可以继续执行其他任务,通过回调函数处理操作完成的通知。
  • 真正的并发操作,不需要阻塞、轮询或信号等待。
  • 需要特定的异步I/O机制或库的支持,编程模式相对复杂。

综合比较,阻塞式I/O模型简单但性能较差,非阻塞式I/O模型通过非阻塞操作提高了性能,I/O多路复用模型可以同时处理多个I/O通道,信号驱动I/O模型可以异步进行I/O操作,而异步I/O模型可以实现真正的并发操作。选择适当的模型取决于应用需求、并发量和性能要求等因素。

525.6.png

注: 本篇文章参考了UNIX网络编程卷1:套接字API.pdf一书,参考了jovan大哥哥的文章,以及个人的见解,文中有错误的地方,希望大家可以指出,希望大家可以见谅。