术语
NIO(Non-blocked IO)
BIO(blocked IO)
AIO(asynchronous I/O)
概念
阻塞/非阻塞
阻塞和非阻塞说的是程序在等待调用结果时的状态,取决与CPU会不会在进程时间片未用尽的情况下进行进程切换,将进程变成非运行状态(挂起进程)。
阻塞调用
accept队列为空的时候,进程被挂起,等accept队列不为空了,cpu再唤醒进程
非阻塞调用
不管accept队列内部情况,每次系统调用accept函数都会立即得到一个返回值,进程不会被挂起
可能阻塞的系统调用:
- 输入操作:read, readv, recv, recvfrom, recvmsg
- 输出操作:write, writev, send, sendto, sendmsg
- 接收外来连接:accept
- 发起外出连接:connect
阻塞IO/非阻塞IO
因为IO操作导致的进程被cpu挂起,唤醒即是阻塞IO和非阻塞IO
同步/异步
同步:
A发出一个’请求’后,一直等待,直到请求执行结束,得到请求的返回值(B发来的)
异步:
A发出一个’请求’后,直接返回,此时并不知道执行的结果/返回值。等其他地方(B)处理请求完成后,把结果主动发过来(A通过回调之类的方法去获取),这个时候A才认为请求执行完成
同步IO/异步IO
异步IO在poxis中的规定: 告诉内核启动某个操作(包括将数据从内核态复制到用户态)完成后通知我们。
需要注意的是同步IO需要进程主动将数据从内核空间拷贝到用户空间,异步则是从内核空间拷贝到用户空间完成后才通知进程。
信号驱动IO就是同步的,因为是内核通知我们何时可以启动IO操作,但IO操作(内核-用户)还未开始
POXIS中的术语:
同步IO操作:
导致请求进程阻塞,直到IO操作完成
异步IO操作:
不导致请求进程阻塞
5种IO的对比
ET触发下,为什么一定要是非阻塞
边缘触发下,用阻塞模型会存在功能上的问题,所以要用非阻塞
当阻塞模式下,recv会一直阻塞接受数据,如果没有一次读取完成所有的数据,ET是边缘触发,只能触发一次epoll_wait更新,剩下的未读取完成的数据就不能继续读入了,除非网络另一端发来新的消息。
同样的,如果一次没有写完,则其他待发送数据,只能等到新的写请求才能触发。所以ET再非阻塞模式下要求循环把数据读取完成。
ET触发下,accept问题
accept事件一次只能从syn就绪队列中取一个放进accept队列,如果同一时刻有多个就绪连接,只accept一次,剩下的连接在下一次epoll_wait也不会触发,LT模式下就没问题
ET模式下,不管阻塞还是非阻塞,都要一次把所有的就绪队列accept成功。可以使用循环。
使用epoll时需要将socket设为非阻塞吗?