本章主要讲用户进程接收并处理数据,主要是介绍,同步阻塞和多路IO复用方案。
同步阻塞
一个进程维护一个链接,同时为了等待数据到来需要阻塞进程,还要切换进程上下文。
- 创建Socket
- 进入内核态,开始 recv data
- 没有当前socket到达的数据时(接收队列里面没有当前socket接收的数据),当前socket 进入等待队列
- 修改当前进程状态为 TASK_INTERRUPTIPLE 可中断状态,同时当前进程进入到阻塞状态,等待被唤醒。
- 数据包到达网卡(外界数据进来)
- 网卡把帧DMA到内存(RingBuffer)
- 硬中断通知CPU
- CPU 向内核线程发起软中断
- 内核线程从RingBuffer上摘下skb(数据包),并创建一个新的skb放上去
- 内核线程把数据放到socket接收队列上
- 唤醒等待队列上的进程
为什么叫做同步阻塞?
在第3步,socket 进入等待队列中,第4步,修改当前进程状态,然后当前进行就进入阻塞状态,然后就不能执行其他的命令了,需要等待对应socket的数据到来。
为什么会性能低呢?
有两次进程上下文的切换,第4步和第11步。第4步:为了等待当前进行阻塞状态,从CPU上拿下来,第10步:睡眠进程被唤醒执行。进程上下文的切换没有意义的工作。
IO多路复用-epoll
一个进程维护上万条链接,性能高效。
epoll
epoll 对象
- wait_queue_head_t wq 等待队列链表,软中断数据就绪的时候会通过wq 来找到阻塞在epoll对象上的用户进程。
- rb_root rbr 一颗红黑树,为了支持对海量链接的高效查找、删除、插入等。通过使用这棵树来管理用户进程下添加进来的所有socket链接。
- list_head rdlist 就绪的描述符的链表,当有链接就绪的时候,内核会把就绪的链接放到 rdllist 里面,这样应用进程只需要判断链表就能找出就绪链接。
epoll 函数
- epoll_create : 创建一个epoll对象
- epoll_ctl : 想 epoll 对象添加要管理的链接
- 分配一个红黑树节点对象epitem。
- 将等待事件添加到socket的等待队列中,同时会注册一个 ep_poll_callback 函数,ep_poll_callback 目的是软中断将数据收到socket的接收队列后,会通过这个ep_poll_callback 函数进行回调,会讲当前socket 添加到rdlist(就绪链表中)。
- 将epitem 插入到epoll 对象的红黑树。
- epoll_wait : 等待其管理的链接上的IO事件 rdlist 是否有数据(就绪状态的socket)
- 有就绪状态的socket,返回socket
- 无就绪状态的socket,当前进程添加到 wq 等待队列中,然后挂起当前进程。等待有数据进来的时候被唤醒。
执行场景
方法名 | 功能 | 执行场景 |
epoll_create | 创建一个epoll对象 | 程序初始化的时候创建 |
epoll_ctl | 想 epoll 对象添加要管理的链接 | socket建立链接的时候,socket创建好了,会创建epoll内核对象 |
epoll_wait | 等待其管理的链接上的IO事件 rdlist 是否有数据 | 1、程序主动初始化的时候会开始epoll_wait 一次 2、等待队列被唤醒的时候会执行 |
有数据进来时
- 将数据保存到socket的接收队列中(这个队列是socket的,不是epoll的)
- 找到对应的回调函数,在创建socket的时候就会给这个socket注册一个回调函数(ep_poll_callback) 该过程在上述的epoll_ctl 函数中执行。
- 执行回调函数
- 通过红黑树找到对应的 epitem。
- 将当前 epitem 添加到对应的 epoll 的就绪队列中。
- 查看epoll 的等待队列是否有进程等待,如果有就唤醒进程。
问题
同步阻塞IO到底是有哪些开销?
- recv 系统调用的时候,如果没有数据了,当前进程就会从当前CPU上拿下来。导致一次进程上下文的切换。消耗cpu
- socket有需要就绪状态就要唤醒对应的进程起来处理数据。又一次进程上下文的切换。消耗cpu
- 一次请求需要一个进程,一个进程需要不少的内存。消耗内存
epoll 也是阻塞的?为什么可以提高网络性能?
epoll的执行流程肯定也是阻塞的,在执行epoll_wait 的时候,如果没有就绪的socket,那他就会被阻塞挂起。当时这并不影响他的性能,因为一个epoll 管理上万个链接,所以上万个链接没有就绪状态的情况比较少。所以并不会出现频繁的挂起现象。这其实就是它性能好的关键。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)