参考链接
-
网络IO的本质:socket的读取,socket在linux系统被抽象为 流,IO可以理解为对流的操作
-
数据会先被拷贝到操作系统 内核的缓冲区 中,然后才会从操作系统内核的缓冲区拷贝到 应用程序的地址空间 (对于 I/O而言)
-
第一阶段:等待数据准备 (Waiting for the data to be ready)
-
第二阶段:将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)
-
-
对于socket流而言
- 第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区
- 第二步:把数据从内核缓冲区复制到应用进程缓冲区
-
网络应用需要处理是两大类问题:网络IO,数据计算
阻塞I/O(BIO)
- 应用程序中进程在发起IO调用后至内核执行IO操作返回结果之前,若发起系统调用的线程一直处于等待状态 ,则此次IO操作为阻塞IO,简称BIO(Blocking IO)
- 当用户进程发起IO系统调用后,内核从准备数据到拷贝数据到用户空间的两个阶段期间用户调用线程选择阻塞等待数据返回(此时的内核也可能将CPU时间切换到了其他需要的进程中)
- BIO 带来的问题:如果内核数据需要耗时很久才能准备好,那么用户进程将被阻塞,浪费性能
非阻塞I/O(NIO)
- 内核接收到请求后就会 立即返回,然后用户进程通过 轮询的方式来拉取处理结果
- NIO问题:任务完成的响应延迟增大,这会导致整体数据吞吐量的降低
- 本质:频繁轮询导致的 无效系统调用
IO多路复用
原理
:不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程
最大优势
:系统开销小,单个process就可以同时处理多个网络连接的IO
I/O多路复用的 主要应用场景
如下:
-
服务器需要同时处理多个处于监听状态或者多个连接状态的套接字
-
服务器需要同时处理多种网络协议的套接字
select 适合少量活跃连接,一般几千;
epoll 适合大量不太活跃的连接
select
- Select:内核提供的系统调用,它支持一次查询多个系统调用的可用状态
- 当任意一个结果状态可用时就会返回,用户进程再发起一次系统调用进行数据读取
- 即NIO中N次的系统调用,借助Select只需要发起一次系统调用
- 但是,select有一个限制:存在连接数限制
poll
- 其与select相比,主要是 解决了连接限制
select/poll虽然减少了用户进程的发起的系统调用,但内核的工作量只增不减
- 用户空间和内核空间之间,大量的数据拷贝
- 内核循环遍历IO状态,浪费CPU时间
- select/poll的问题本质是:内核存在无效的循环遍历
epoll
- 相较于select/poll,多了两次系统调用
- epoll_create 建立与内核的连接,epoll_ctl 注册事件,epoll_wait 阻塞用户进程,等待IO事件
信号驱动IO(SIGIO)
- 信号驱动IO与BIO/NIO最大的区别就在于:在IO执行的数据准备阶段,不会阻塞用户进程
- 但在IO执行的第二阶段(将数据从内核空间复制到用户空间):用户进程还是被阻塞的
- 这种方式在平常并不常用
异步IO(AIO)
- 真正实现了IO 全流程的非阻塞
- 用户进程发出系统调用后立即返回,内核等待数据准备完成,然后将数据拷贝到用户进程缓冲区,然后发送信号告诉用户进程IO操作执行完毕(与SIGIO相比,一个是发送信号告诉用户进程数据准备完毕,一个是IO执行完毕)