我们在创建服务器监听套接字时,通过多线程多进程进行监听连接客户端太浪费cpu资源,所以引入IO多路复用模型进行监听
select模型:
优点:跨平台。win、linux、macos、Uinx
缺点:监听上限受文件描述符限制,1024
监测满足条件的fd, 自己添加效率低,编码难度有所上升(业务能力低)
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
函数原型: int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
大致流程如下:
1)用户空间发起 select系统调用,将监听的fd
集合从用户空间拷贝到内核空间
2)内核遍历fd集合,检查数据是否就绪
3)如果遍历一遍后发现没有fd就绪,则会将当前
用户进程阻塞,让出CPU给其他进程
4)当客户端将数据发送到服务端,进入内核后,
会通过数据库包找到对应的 socket
PS:客户端发送数据到数据进入服务端内核的流
程类似下面 epoll的流程
5) socket检查是否有阻塞等待的进程,如果有则
唤醒该进程
6)用户进程恢复运行后,会再遍历fd集合进行检
查,此时它会检查到某些fd已经就绪了,它会给
这些fd打上标记,然后结束阻塞,返回到用户空
间
7)用户空间知道有事件就绪,遍历fd集合,找到
就绪的fd,进行相应的事件处理,例如将数据从
内核缓冲区拷贝到应用程序缓冲区
8)最后执行逻辑处理。
poll:
与select基本一致,优化了文件描述符上限不需要每次重置fd_set;
epoll:
核心流程
1)应用程序调用epoll create,内核会分配一块
内存空间,创建一个epoll,最后将 epoll的fd返
回,我们后续可以通过这个fd来操作 epoll对象
2)应用程序不断调用epoll将我们要监听的f
d维护到 epoll,内核通过红黑树的结构来高效的
维护我们传入的fd集合
3)应用程序调用epoll wait来获取就绪事件,内
核检查 epoll的就绪列表,如果就绪列表为空则会
进入阻寒,否则直接返回就绪的事件
4)应用程序根据内核返回的就绪事件,进行相应
的事件处理