目录
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
1. 历史定位
迄今为止,linux平台性能最好的IO多路转接模型。没有之一。
2. 接口
2.1 创建epoll句柄
int epoll_create(int size);
参数:
size:目前没有含义了,但是需要大于0,兼容旧内核返回值:返回的epoll操作句柄;
2.2 操作epoll
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
参数:
epfd :
epoll操作句柄
op :当前要执行的行为
- EPOLL_CTL_ADD
- 添加一个文件描述符对应的事件结构到epoll当中
- EPOLL_CTL_MOD
- 修改一个文件描述符的事件结构
- EPOLL_CTL_DEL
- 从epoll当中删除一个文件描述符对应的事件结构
fd:
待处理(添加,修改,删除)的文件描述。
event:
文件描述符对应的事件结构event中events是我们要关心的事件,这里如果同时多个事件那么我们也用或的方式连接。
返回值:
0正常。
-1失败。
2.3 获取就绪事件结构
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
参数:
epfd :
epoll的操作句柄
events :
事件结构数组(集合),从epoll当中获取就绪的事件结构
maxevents :
最多一次获取多少个事件结构
timeout :
- >0 :带有超时事件
- ==O:非阻塞
- <0:阻塞
返回值:
就绪的文件描述符个数
3. epoll监控的内部工作原理
这里epoll监控的内部工作原理:整个epoll的工作原理就是调用epoll_create创建红黑树和双向链表这两个数据结构,然后我们用epollctr将要监控的文件描述符添加到红黑树中,添加到红黑树中,然后epoll就再内核中帮我们一直监控遍历红黑树,有就绪事件发送就添加到双向链表中,然后通过epoll_wait从双向链表当中获取就绪事件。
4. epoll简单服务端多路转接服务器
这里我们可以先封装一个对于服务端的tcp类,来为服务端提供tcp服务。
然后我们来实现一个epoll的监控
我们运行代码可以看到多个客户端连接服务端并向其发送消息服务端都可以接收到。
5. epoll的工作模式
默认工作模式:LT水平触发
LT︰水平触发(“亲妈”模式:只要达到触发事件的条件,则一定乐此不疲的触法。);友好
换个说法:当读就绪或者写就绪的时候,则一定乐此不疲的通知。举个例子当我们用epoll监听新连接套接字的时候,当就新连接套接字就绪的时候也就是接收缓冲区中有消息的时候那么这时epoll会一直通知处理。直到接收缓冲区中消息都被读出。
ET∶边缘触发(“后妈”模式:当到达触发事件的条件后,只会触发一次);
要求程序员一次将数据全部读回来换个说法:当读就绪或者写就绪的时候,只会通知一次。举个例子当我们用epoll监听新连接套接字的时候,当就新连接套接字就绪的时候也就是接收缓冲区中有消息的时候那么这时epoll只通知一次,也就是当我们用epoll_wait来获取就绪事件的数组的时候只有这一次会将就绪事件的获取到。之后就无法获取。所以这就要求我要一次性将数据全部都读取回来。
这里的水平触发和边缘触发是针对某个文件描述符来说的。这里在设置某个事件是水平触发还是边缘触发只需要将文件描述符的关心事件events或一个EPOLLET就可以了。
这里验证边缘触发,将新连接套接字的工作方式换为非阻塞和边缘触发方式。非阻塞是因为这里如果当接收缓冲区中刚好没有数据了,但是此时还要接收那么recv就会进入阻塞状态。
tcp服务端: