Linux 网络I/O模型

2022/1/12 7:03:57

本文主要是介绍Linux 网络I/O模型,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Linux 网络I/O模型

1. 阻塞IO模型

img

最常用的I/O模型,缺省情形下,所有文件操作都是阻塞的。进程空间调用recvfrom函数,直到数据包到达且被复制到应用进程的缓冲区中或者发生错误时才返回,在此期间,进程会被阻塞一直等待。

2. 非阻塞IO模型

img

recvfrom函数当发现内核缓冲区没有数据时,直接返回一个EWOULDBLOCK错误,一般通过轮询检查这个状态,看内核是否有数据到来。

3. IO复用模型

img

fd:文件描述符。一个文件的读写操作会调用内核提供的系统命令,返回一个fd

socketfd:一个socket的读写的对应的描述符

  • linux提供select/poll,进程通过将一个或多个fd传递给select或poll系统调用,阻塞在select操作上,这样select/poll可以通过顺序扫描多个fd帮我们侦测是否处于就绪状态。(select/poll 是顺序扫描fd是否就绪,也就是轮询,支持的fd的数量有限)
  • linux还提供了一个epoll系统调用,基于事件驱动方式代替顺序扫描,性能更高。当有fd就绪时,立即回掉函数rollback。

IO多路复用技术

当需要同时处理多个客户端接入请求时,可以利用多线程或IO多路复用技术进行实现。原理是:通过把多个IO的阻塞复用到同一个select的阻塞上,从而使得系统在单线程的情况下也可以同时处理多个客户端请求。

IO多路复用最大优势:系统开销小。即系统不需要创建新的额外进程或线程,也不需要维护这些这些进程和线程的运行,降低了系统的维护工作量,节省了系统资源。

IO多路复用主要应用场景:①服务器需要同时处理多个处于监听或连接状态的套接字。②服务器需要同时处理多种网络协议的套接字。

支持IO多路复用的系统调用有selectpselectpollepoll。在linux网络编程中,很长时间使用select,但select的一些固有缺陷导致了它的应用受到了很大的限制,最终Linux选择了epoll。

epoll改进的select缺点如下:

  1. 支持一个进程打开的socket描述符(FD)不受限制(仅受限于操作系统的最大文件句柄数)。

    select最大缺陷是单个进程打开的FD是有限制的,由FD_SETSIZE设置,默认是1024。对于那些需要支持上万个TCP连接的大型服务器来说太少了。

    epoll并没有这个限制,它所支持的FD上限是操作系统的最大文件句柄数。比如:在1G内存大小的机器上大约是10万个句柄左右,具体值可以通过cat /proc/sys/fs/file-max查看。

  2. IO效率不会随着FD数目的增加而线性下降。

    传统的select/poll的另一个弱点:当你拥有一个很大的socket集合时,由于网络延迟或者链路空闲,任一时刻只有少部分的socket时“活跃” 的,但是select/poll每次调用都会轮询全部的集合,导致效率呈现线性下降。

    epoll不存在这个问题,它只会对“活跃”的socket进行操作。原因是在内核实现中,epoll是根据每个fd上面的callback函数实现的。只有活跃的socket才会主动调用callback函数,其他idle状态的socket不会。epoll实现了一个伪AIO。

  3. 使用mmap加速内核与用户空间的消息传递。

    内核需要把FD消息通知给用户空间,如何避免不必要的内存复制就显得非常重要。epoll通过内核和用户空间mmap同一块内存来避免不必要的内存复制。

  4. epoll的API更加简单

    包括创建一个epoll描述符、添加监听事件、阻塞等待所监听的事件发生、关闭epoll描述符等。

用来克服select/poll缺点的方法不只有epoll,epoll只是一种Linux的实现方案。在freeBSD(一种类UNIX操作系统)下有kqueue(实际上是一个功能相当丰富的kernel事件队列,不仅仅是select/poll的升级,还可以处理signal、目录结构变化、进程等多种事件),而dev/poll 是最古老的Solaris的方案,使用难度依次递增。

4. 信号驱动IO模型

首先开启套接字信号驱动IO功能,并通过系统调用sigaction执行一个信号处理函数。它是非阻塞的。当数据准备就绪后,会为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据,并通知主循环函数处理数据。

5. 异步IO模型

img

告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核复制到用户自己的缓冲区)通知我们。同样是非阻塞的。

这种模型与信号驱动模型的主要区别是:信号驱动IO由内核通知我们何时可以开始一个IO操作;异步IO模型由内核通知我们IO操作何时已经完成。



这篇关于Linux 网络I/O模型的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程