Epoll用法及读写触发条件

Epoll用法及读写触发条件,第1张

一、函数解析

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

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

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

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

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)

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 <stdio.h>

#include <sys/epoll.h>

#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 = 0i <nfdsi++) {

       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 的API用来执行类似poll()的任务。能够用于检测在多个文件描述符中任何IO可用的情况。Epoll API可以用于边缘触发(edge-triggered)和水平触发(level-triggered), 同时epoll可以检测更多的文件描述符。以下的系统调用函数提供了创建和管理epoll实例:

边缘触发(edge-triggered 简称ET)和水平触发(level-triggered 简称LT):

epoll的事件派发接口可以运行在两种模式下:边缘触发(edge-triggered)和水平触发(level-triggered),两种模式的区别请看下面,我们先假设下面的情况:

如果rfd被设置了ET,在调用完第五步的epool_wait 后会被挂起,尽管在缓冲区还有可以读取的数据,同时另外一段的管道还在等待发送完毕的反馈。这是因为ET模式下只有文件描述符发生改变的时候,才会派发事件。所以第五步 *** 作,可能会去等待已经存在缓冲区的数据。在上面的例子中,一个事件在第二步被创建,再第三步中被消耗,由于第四步中没有读取完缓冲区,第五步中的epoll_wait可能会一直被阻塞下去。

下面情况下推荐使用ET模式:

相比之下,当我们使用LT的时候(默认),epoll会比poll更简单更快速,而且我们可以使用在任何一个地方。

先简单的看下EPOLL的API

epoll_create() 可以创建一个epoll实例。在linux 内核版本大于2.6.8 后,这个 size 参数就被弃用了,但是传入的值必须大于0。

epoll_create() 会返回新的epoll对象的文件描述符。这个文件描述符用于后续的epoll *** 作。如果不需要使用这个描述符,请使用close关闭。

epoll_create1() 如果 flags 的值是0,epoll_create1()等同于epoll_create()除了过时的size被遗弃了。当然 flasg 可以使用 EPOLL_CLOEXEC,请查看 open() 中的O_CLOEXEC来查看 EPOLL_CLOEXEC有什么用。

返回值: 如果执行成功,返回一个非负数(实际为文件描述符), 如果执行失败,会返回-1,具体原因请查看error.

这个系统调用能够控制给定的文件描述符 epfd 指向的epoll实例, op 是添加事件的类型, fd 是目标文件描述符。

有效的op值有以下几种:

event 这个参数是用于关联制定的 fd 文件描述符的。它的定义如下:

events 这个参数是一个字节的掩码构成的。下面是可以用的事件:

返回值: 如果成功,返回0。如果失败,会返回-1, errno 将会被设置

有以下几种错误:

epoll_wait 这个系统调用是用来等待 epfd 中的事件。 events 指向调用者可以使用的事件的内存区域。 maxevents 告知内核有多少个events,必须要大于0.

timeout 这个参数是用来制定epoll_wait 会阻塞多少毫秒,会一直阻塞到下面几种情况:

timeout 等于-1的时候这个函数会无限期的阻塞下去,当 timeout 等于0的时候,就算没有任何事件,也会立刻返回。

struct epoll_event 如下定义:

每次epoll_wait() 返回的时候,会包含用户在epoll_ctl中设置的events。

还有一个系统调用epoll_pwait ()。epoll_pwait()和epoll_wait ()的关系就像select()和 pselect()的关系。和pselect()一样,epoll_pwait()可以让应用程序安全的等待知道某一个文件描述符就绪或者捕捉到信号。

下面的 epoll_pwait () 调用:

在内部等同于:

如果 sigmask 为NULL, epoll_pwait()等同于epoll_wait()。

返回值: 有多少个IO事件已经准备就绪。如果返回0说明没有IO事件就绪,而是timeout超时。遇到错误的时候,会返回-1,并设置 errno。

有以下几种错误:


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/tougao/11177841.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-14
下一篇 2023-05-14

发表评论

登录后才能评论

评论列表(0条)

保存