1. 什么是网络IO
网络IO和磁盘IO一样,也是IO的一种。磁盘IO是磁盘-->内核-->应用程序,同样网络IO是网卡-->内核-->应用程序。简单理解,就是操作系统收到网卡的数据,然后缓存到一个缓冲区buffer中,然后应用程序调用系统函数,从buffer中取数据。
访问IO的方式,也就是通常所说的IO模型,大致有五种,分别是阻塞IO、非阻塞IO、多路复用IO(selecet\poll\epoll等)、信号驱动IO以及异步IO。《Unix网络编程》一书中都有提及,本文主要将的是应用最广泛的多路复用。
2. 网络IO模型
所有的网络模型解决的核心问题都是以下3个问题:
1. 有哪些网络连接?
2. 哪个连接有数据?
3. 如何读取数据?
2.1 阻塞IO
这是最简单的一种IO,已recvfrom为例子,应用进程执行系统调用之后,会一直阻塞,直到数据包到达且返回到应用进程的缓冲区或者出错的时候。但是这个时候,服务端一直被占用,就没法再接收新的客户端的请求了。
2.2 非阻塞IO
与阻塞IO相比,它不再一直等待,而是通过间隔轮训的方式,去查看操作是否就绪。如果我有很多,比如10000个连接,一个连接建立平均轮训4次的话就是40000次系统调用,内核态和用户态频繁的切换,成本是非常高的,最终拖慢系统的响应。
2.3 信号驱动IO
当操作就绪之后,内核会发送信号SIGIO给应用进程,应用进程在此期间不被阻塞。但是当数据量大,会频繁的产生信号(但也只是一个信号,并没告诉应用发生了什么)内核不断拷贝数据到用户态,性能变低。
2.4 异步IO
告诉内核启动了某个操作,等整个操作完成之后,再通知应用进程。这是一种理想的IO模型,等待过程中进程不被阻塞,和信号驱动IO也不同,它发送信号,已完成数据传送。不过glibc 的 aio 还不成熟。
2.5 IO多路复用
多路复用,单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。它的优点是只用一个线程就可以管理多个socket,无需新建线程或者进程,减少了资源消耗。连接越多它的优势越明显,但若只有很少数的连接,可能比阻塞IO+多线程效率还低。
Linux上常用的IO多路复用器主要有select、poll、epoll
[1] http://www.360doc.com/content/18/0624/05/56167096_764796454.shtml
[2] https://blog.youkuaiyun.com/weixin_42962086/article/details/109478700
[3] UNIX网络编程