关键结构体
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
其中data用来存放套接字;
其中
events能够是下面几个宏的集合:
EPOLLIN :表示相应的文件描写叙述符能够读(包含对端SOCKET正常关闭);
EPOLLOUT:表示相应的文件描写叙述符能够写。
EPOLLPRI:表示相应的文件描写叙述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示相应的文件描写叙述符错误发生;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式。这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:仅仅监听一次事件。当监听完这次事件之后,就会把这个fd从epoll的队列中删除。
EPOLLHUP:表示相应的文件描写叙述符被挂断,
EPOLLRDHUP是:从Linux内核2.6.17开始由GNU引入的事件。当socket接收到对方关闭连接时的请求之后触发,有可能是TCP连接被对方关闭,也有可能是对方关闭了写操作。如果不使用EPOLLRDHUP事件,我们也可以单纯的使用EPOLLIN事件然后根据recv函数的返回值来判断socket上收到的是有效数据还是对方关闭连接的请求。
EPOLLHUP与EPOLLRDHUP的区别
PEOLLRDHUP
EPOLLRDHUP 表示读关闭。不是所有的内核版本都支持,没有查证。有两种场景:
1、对端发送 FIN (对端调用close 或者 shutdown(SHUT_WR)).
2、本端调用 shutdown(SHUT_RD). 当然,关闭 SHUT_RD 的场景很少。
EPOLLRDHUP 可以作为一种读关闭的标志,注意不能读的意思内核不能再往内核缓冲区中增加新的内容。已经在内核缓冲区中的内容,用户态依然能够读取到。
EPOLLHUP 表示读写都关闭:
1、本端调用shutdown(SHUT_RDWR)。
2、本端调用 shutdown(SHUT_WR),对端调用 shutdown(SHUT_WR)。
3、对端发送 RST.
发送 RST 的常见场景。
- 系统崩溃重启(进程崩溃,只要内核是正常工作都还能兜底,发送的是FIN,不是这里讨论的RST),四元组消失。此时收到任何数据,都会响应 RST.
2)设置 linger 参数,l_onoff 为 1 开启,但是 l_linger = 0 超时参数为0. 此时close() 将直接发送 RST.
- 接收缓冲区中还有数据,直接 close(), 接收缓冲区中的内容丢弃,直接发送 RST.
4)调用 close 时,close 会立马发送一个 FIN。注意:仅仅从 FIN 数据包上,无法断定对端是 close 还是仅仅 shutdown(SHUT_WR) 半关闭。往对端发送数据,若对端已经 close(),对端会回复 RST.
创建内核事件表
int epoll_create(int size);
参数:可以监控套接字的最大个数,但是在 Linux 2.6.8 内核版本以后,这个参数内核已经不再处理了(就是没有限制了),但是必须要大于1;
返回值:成功返回epoll文件描述符;失败返回-1
将需要监听的事件和对应的套接字绑定起来,并通过内核事件表的文件描述符对其操作
int epoll_ctl(int epfd, int op, int fd, struct epoll_event * event);
参数1:epoll描述符
第2个参数:对套接字绑定的事件进行相关操作:
op表示动作:用三个宏表示:
EPOLL_CTL_ADD:注冊新的fd到epfd中;
EPOLL_CTL_MOD:改动已经注冊的fd的监听事件;当某个fd已经注册了事件,只能修改不能新增,新增则报错;
EPOLL_CTL_DEL:从epfd中删除一个fd;
第3个参数:套接字文件描述符
第4个参数:内核事件表
返回值:成功返回0,失败返回非0
阻塞等待监听的事件发生
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
第一个参数:epoll描述符
第二个参数:第二个参数内核事件表
第三个参数;内核时间表中事件最大数
返回值:成功返回要处理的事件数,失败返回-1,超时返回0
作用:阻塞等待事件发生,返回须要处理的事件的数量,并将需处理事件的套接字集合于參数events内。參数timeout是超时时间(毫秒,0会马上返回(noblocking)。-1是永久堵塞)。该函数返回须要处理的事件数目。如返回0表示已超时。
使用epoll的DEMO如下
服务器端
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#</