1.Linux网络IO模型
1.1 同步和异步、阻塞和非阻塞的区别
- `同步`:调用方需要主动等待结果的返回。
- `异步`:调用方调用了函数不需要等待结果的返回,后续通过回调等手段来处理结果。
- `阻塞`:在调用方拿到结果之前,线程会被挂起,不能做任何事。
- `非阻塞`:在调用方拿到结果之前,线程可以执行一些其他的事情,不会被挂起。
1.2 同步、异步、阻塞、非阻塞的相互组合模式
- `同步阻塞模式`:最常见的组合模式,调用方在拿到结果之前,线程处于挂起状态,直到有数据触达为止。
- `同步非阻塞模式`:调用方发起了函数调用,通过轮询的方式来检查结果,这个过程线程并未阻塞,但是轮询的目的是等待结果的返回。
- `异步阻塞模式`:最不常用的方式,这种方式没有发挥出异步的真实效果。
- `异步非阻塞模式`:调用方发起函数调用后,给接受方一个回调函数,然后自己去执行其他的方法。后续接受方有了数据后主动调用回调函数来实现结果的返回。
1.3 Linux的5种IO模型
Linux的5种IO模型:阻塞IO、非阻塞IO、IO多路复用、信号驱动IO、异步IO,前面四种都是同步的模式,只有最后一种是异步的。 注:Java的BIO和Linux的BIO是一致的,但是Java里面的NIO对应的是Linux的IO多路复用。
1.3.1 阻塞式IO(BIO)
1.3.2 非阻塞式IO(NIO(并非Java里面的NIO))
1.3.3 IO多路复用
IO多路复用的方式会有2次系统调用,从这一点看并不比BIO有优势。IO多路复用相比于BIO来说最大的优势就是可以用select少量的线程处理多个连接请求。 所以,在连接量少的情况下,BIO的效率反而更好,IO多路复用则是在大连接量场景有优势。
1.3.4 信号驱动式IO
通过进程的SIGIO信号作为事件驱动来进行IO的处理,这种模式运用比较少。
1.3.5 异步IO模型
2.Linux的IO多路复用
IO多路复用机制就是通过一个进程可以监视多个文件描述符,一旦有socket描述符就绪,就能够通知应用程序做对应的读写处理。
2.1 文件描述符 File Descriptor(FD)
在Linux系统中,文件、外接设备、套接字socket都视为文件,统一文件接口方便操作系统访问。同理,Socket套接字也是一种文件,当应用程序请求内核打开一个文件时,内核就会为此返回一个文件描述符。
2.2 IO多路复用的实现方案
Linux的IO多路复用有3种实现手段:select、poll、epoll:
2.2.1 select
select函数可以监视3类文件描述符:writeFds、readFds、execptFds。调用select函数后进程会阻塞,直到有就绪的文件描述符。当select又返回时,就会唤醒进程来处理io事件,而且是会遍历整个描述符数组来处理就绪的io事件。 select的优点是跨平台支持,缺点是单个进程的文件描述符是有OS控制的,Linux最大是1024个,但是可以修改。另一个缺点就是需要遍历整个文件描述符数组。
2.2.2 poll
和select十分相似,只不过poll对文件描述符的管理时基于链表,而且poll没有限制描述符数量,当连接量较大时性能会急剧下降。和select一样,调用poll函数后,一旦有就绪事件需要轮询整个链表。
2.2.3 epoll
epoll是在Linux2.6版本推出的一种IO多路实现手段。相对于poll和select,epoll做了很大优化和改进。
epoll的优化思路有2点:
1. 功能分离:创建epoll、socket监视注册、等待数据分为3个API实现。
1. 就绪列表:select和poll低效的根本原因是要遍历所有的socket,epoll则维护了一个就绪列表,引用了收到了数据的socket,这样就避免了全链表扫描。
当socket收到数据后,中断程序会操作eventpoll,将对应的socket挂载到就绪列表里面,后续恢复进程来处理,此时只需要处理就绪列表里面的socket。 当进程调用epoll_creat函数时,Linux内核会创建一个Eventpoll结构体,然后在内核缓冲区中创建一个红黑树来存储后续连接注册的socket,然后也会在Eventpoll中创建一个就绪链表。后续只需要监听这个链表有没有就绪的socket即可。 epoll相对于select和poll有了很大的优势,保持数万数十万连接也不是问题。但是在极端情况下,例如就序列表的元素十分多时,也会有瓶颈。
2.3 触发方式
2.3.1 水平触发 LT
当被监控的文件描述符上有可读写事件发生时,epoll_wait( )会通知应用程序去读写,如果这次读写没有处理完数据,那么下次调用epoll_wait( )是,OS还会继续通知应用程序继续读写,如果你一直不处理完数据,OS会一直通知你。
2.3.2 边缘触发 ET
和水平触发不同的是,应用程序没有处理完这一次通知事件的数据时,调用epoll_wait( )时OS并不会通知你有数据读写事件,直到这个文件描述符上出现第二次可读写事件发生时才通知应用程序。这种方式相比LT,ET更加清净,一般来说ET性能要高于LT,但是实际应用中看不出有啥大区别。
|