一、网络I/O的本质
网络I/O的本质是socket的读取,socket在linux系统被抽象为流,I/O可以理解为对流的操作。这个操作又分为两个阶段:
-
等待流数据准备(wating for the data to be ready)。
-
从内核向进程复制数据(copying the data from the kernel to the process)。
对于socket流而言,
-
第一步通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。
-
第二步把数据从内核缓冲区复制到应用进程缓冲区。
二、阻塞io(block/io)和非阻塞io(noblock/io)
阻塞:阻塞就是进程 “被” 休息, CPU处理其它进程去了。
需要注意,拷贝数据整个过程,进程仍然是属于阻塞的状态。
阻塞的过程:
1、主进程的socket执行recvform系统调用,
2、进程被挂起,CPU执行其他进程
3、recvform得到数据,内核发送信号给进程,进程被唤醒,调用。
4.1、第一步:recvform得到的数据分组到达,然后被复制到内核的某个缓冲区。
4.2、第二步把数据从内核缓冲区复制到应用进程缓冲区。
5.进程获取cpu权限,处理数据
非阻塞的过程:
1.0、主进程的socket执行recvform系统调用,
1.1、系统马上返回"error",代表“无数据报表准备好”
1.2、主进程的socket执行recvform系统调用,
1.3、系统马上返回"error",代表“无数据报表准备好”
...主进程持续轮询
2、recvform得到数据,内核发送信号给进程,进程被唤醒,调用。
3.1、第一步:recvform得到的数据分组到达,然后被复制到内核的某个缓冲区。
3.2、第二步把数据从内核缓冲区复制到应用进程缓冲区。
4.进程获取cpu权限,处理数据
三、多路复用io(multiplexing I/O)
多路复用有两个特别的系统调用select或poll。select调用是内核级别的。
select和阻塞的区别:select可以监听多个socket,阻塞只有一个
select默认监听的最大数量:1000个,(linux系统也可以修改,因为select
是内核级别的)
poll最大监听数量:无限制
select的过程:
1、主进程的socket执行recvform系统调用,select接收到recvform动作。
2、进程被挂起,CPU执行其他进程
3.0、select执行recvform系统调用,
3.1、系统马上返回"error",代表“无数据报表准备好”
3.2、select执行recvform系统调用,
3.3、系统马上返回"error",代表“无数据报表准备好”
...select持续轮询
3.4、recvform得到数据,内核发送信号给select,select发送信号给进程,进程被唤醒,调用。
4.1、第一步:recvform得到的数据分组到达,然后被复制到内核的某个缓冲区。
4.2、第二步把数据从内核缓冲区复制到应用进程缓冲区。
5.进程获取cpu权限,处理数据
从整个I/O过程来看,阻塞、非阻塞、select/poll,他们都是顺序执行的,因此可以归为同步模型(asynchronous)。都是进程主动向内核检查。
四、异步io(asynchronous I/O)
epoll:保存了一个“已接送数据报文的socket列表”,轮询的是已完成的列表,所以比select高效。
epoll监听最大数量:无限制
注意:和前面的 同步模型 不同,异步模型是由内核向进程发送完成信号的。
相对于同步I/O,异步I/O不是顺序执行。
用户进程进行aio_read系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情。
等到socket数据准备好了,内核直接复制数据给进程,然后从内核向进程发送通知。
I/O两个阶段,进程都是非阻塞的。
epoll的过程:
1、主进程的socket执行recvform系统调用,epoll接收到recvform动作。
2、进程被挂起,CPU执行其他进程。
3.0、recvform得到数据。
3.1、数据报文复制到内核缓存区,
3.2、内核缓存区的数据复制到进程缓存区,
3.3、内核发送"已完成"信号给进程,
3.4、epoll轮询"已完成的socket列表",
4、进程被唤醒,进程获取cpu权限,处理数据。