Epoll用法及读写触发条件

struct epoll_event {

    __uint32_t events;      /* Epoll events */

    epoll_data_t data;      /* User data variable */

};

一、函数解析

#include

int epoll_create(int size)

1. size不是最大值,而是内核如何对内部结构进行维度设置的提示。

2. epoll_create返回的文件描述符必须使用close关闭。

返回值:成功(非负文件描述符) 失败(-1)

errno(EINVAL-size非正 | ENFILE-文件描述符用完 | ENOMEM-内存不足)

#include

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) 

events成员有:

EPOLLIN 关联的文件描述符可读

EPOLLOUT 关联的文件描述符可写

EPOLLRDHUP 流式套接字对端关闭连接或关闭写通道(ET模式写非常有用)2.6.17

EPOLLPRI 关联的文件描述符紧急数据可读

EPOLLERR 关联的文件描述符发生错误

EPOLLHUP  关联的文件描述符挂起

EPOLLET ET模式

EPOLLONESHOT 关联的文件描述符设置一次性行为 2.6.2

op操作有:

EPOLL_CTL_ADD 增加

EPOLL_CTL_MOD 修改

EPOLL_CTL_DEL 删除

返回值:成功(0) 失败(-1)

errno(EBADF-epfd或者fd不是合法的 | EEXIST-重复增加 | EINVAL-epfd不是epoll描述符或者epfd=fd | ENOENT-修改删除的fd不在epoll中 | ENOMEM-内存不足 | EPERM-fd不支持epoll)

#include

int epoll_wait (int epfd, struct epoll_event *events, int maxevents, int timeout);

int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask);

1. timeout为0表示立马返回, 为-1表示无限等待

2. 超时或者达到maxevents都会返回

返回值:成功(就绪的文件描述符数量) 失败(-1)

errno(EBADF-epfd不合法 | EFAULT-events没有写权限 | EINTR-超时 | EINVAL-epfd不是epoll描述符或者maxevents小于0) 

二、写过程

水平触发(LT):只要写缓冲区还有空间,就返回写就绪。

边缘触发(ET):

    1.首次加入epoll且写缓冲区有空间,返回写就绪(参考四用例第一次调用printf)

    2.写缓冲区内容被取走,返回写就绪(参考四用例的fflush,\n有类似作用)

    3.EPOLL_CTL_MOD修改关联文件描述符event,且写缓冲区有空间,返回写就绪(参考四用例epoll_ctl)

三、读过程

水平触发:只要读缓冲区有数据,就返回可读。

边缘触发:

    数据到来的时候返回可读。(即如果上一次没有读完的数据,需要等到下一次数据到来的时候才能继续读)。


四、用例(写过程)

#include

#include

#define STDOUT_FILENO 1

int main(void) {

  int epfd, nfds;

  struct epoll_event ev, events[5]; //ev用于注册事件,数组用于返回要处理的事件

  epfd = epoll_create(1); //只需要监听一个描述符——标准输出

  ev.data.fd = STDOUT_FILENO;

  ev.events = EPOLLOUT | EPOLLET; //监听读状态同时设置ET模式

  epoll_ctl(epfd, EPOLL_CTL_ADD, STDOUT_FILENO, &ev); //注册epoll事件

  for (;;) {

    nfds = epoll_wait(epfd, events, 5, -1);

    for (int i = 0; i < nfds; i++) {

       if (events[i].data.fd == STDOUT_FILENO) {

           printf( "hello world!");

//         ev.data.fd=STDOUT_FILENO;

//         ev.events=EPOLLOUT|EPOLLET;

//         epoll_ctl(epfd,EPOLL_CTL_MOD,STDOUT_FILENO,&ev); //重新MOD事件(ADD无效),返回写就绪,循环输出

//         fflush(stdout); //读取写缓冲区数据,返回写就绪,循环输出

}}}}

五、如何判断客户端关闭连接

1. TCP recv返回0, 说明对方关闭

2. 注册EPOLLERR, 收到事件是关闭

3. recv/send 返回-1时, 如果错误不是EWOULDBLOCK或者EINTR, 也主动关闭连接。

你可能感兴趣的:(Epoll用法及读写触发条件)