ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

linux网络编程一:epoll

2021-04-16 09:51:36  阅读:152  来源: 互联网

标签:文件 epoll 编程 列表 描述符 linux 就绪 wait


简介

一提到linux高性能服务器编程,epoll就是绕不开的话题,当前网络库在linux上实现也主要是以epoll为主。epoll的主要优点有:

  • 当检查大量的文件描述符时,epoll的性能比select和poll要高很多。
  • epoll 既支持水平触发也支持边沿触发。select 和 poll只支持水平触发,而信号驱动I/O只支持边缘触发。
  • 避免复杂的信号处理流程
  • 灵活性高,可以指定希望检查的事件类型

API

epoll由以下api构成:epoll_Create1, epollctl以及epoll_wait。

epoll_Create1

epoll_Create1 用于创建一个epoll实例,并返回代表该实例的文件描述符,epoll_Create1 支持传入一个可用来修改系统调用行为的flags参数,目前支持一个flag标志:EPOLL_CLOEXEC, 使得内核在新的文件描述符上启动执行即关闭标志。

epoll_ctl

epoll_ctl用来修改epoll实例中的兴趣列表,函数声明:

#include <sys/epoll.h>
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* ev);
return 0 on success, or -1 on error
复制代码

参数简介:

  • epfd - epoll实例
  • op 指定需要执行的操作
操作描述
EPOLL_CTL_ADD将描述符fd添加到opell实例中的兴趣列表中,如果文件描述符已经存在,则epoll_ctl返回EEXIST错误
EPOLL_CTL_MOD修改描述符fd上设定的事件,如果描述符不存在,epoll_ctl返回ENOENT错误
EPOLL_CTL_DEL将描述符fd从epoll实例兴趣列表中删除,如果描述符不存在,epoll_ctl返回ENOENT错误, 关闭文件描述符会自动的将其从所有的epoll实例兴趣列表中移除
  • fd - 文件描述符,可以是管道、FIFI、套接字、POSIX消息队列、终端、设备等,但不能是普通文件或目录的文件描述符(会出现EPERM错误)
  • ev

ev 是指向结构体epoll_event的指针,结构体定义如下:

struct epoll_event{
	uint32_t events;
	epoll_data_t data;
};
复制代码

events字段是一个位掩码, 表示描述符fd上感兴趣的事件集合。 data字段是一个联合体,联合体成员可以用来指定传回给调用进程的信息, 其类型为:

typedef union epoll_data{
	void      *ptr;
	int       fd;
    uint32_t  u32;
    uint64_t  u64;
}epoll_data_t;
复制代码

  • max_user_watches 上限

因为每个注册epoll实例中的描述符需要占用一小段不能被交换的内核内存空间,因此, 内核提供了一个接口用来定义每个用户可以注册到epoll实例上的文件描述符总数,这个上限值可以通过max_user_watches来查看和修改。 max_user_watches是linux系统/proc/sys/fs/epoll目录下的一个文件,上限值可以根据可用的系统内存来计算得出。

epoll_wait

epoll_wait返回epoll实例中处于就绪状态的文件描述符信息,单次epoll调用可以返回多个就绪态文件描述符信息。

#include <sys/epoll.h>
int epoll_wait(int epfd, struct epoll_event *evlist, int maxevents, int timeout);
复制代码

参数简介:

  • epfd - epoll实例
  • evlist - 指向包含就绪状态文件描述符的结构体数组,列表中每个元素代表就绪的文件描述符,events字段代表已经就绪的事件掩码,data字段是使用epoll_ctl注册事件时ev.data中所指定的值,也是同事件相关联的文件描述符。
  • maxevents - evlist的个数
  • timeout - 用来决定epoll_wait的行为:
timeoutepoll_wait的行为
-1epoll_wait将一直阻塞,直到兴趣列表中的文件描述符有事件产生
0epoll_wait 执行一次非阻塞式的检查
>0epoll_wait 至多阻塞timeout毫秒

调用成功之后,epoll_wait返回数组evlist中的元素个数,如果超时或者没有文件描述符就绪,则返回0, 出错时返回-1,并在errno中设定错误码以表示错误原因。 可以在一个线程中使用epoll_ctl将文件描述符添加到另一个线程中由epoll_wait所监视的epoll实例的兴趣列表中,并且,修改的兴趣列表将立刻得到处理。epoll_wait也会返回新加入文件描述符的就绪信息。

epoll 事件

epoll事件可以通过ev.events中的位掩码指定,events字段上的位掩码值

位掩码作为epoll_ctl的输入作为epoll_wait的返回描述
EPOLLIN可读取非高优先级的数据
EPOLLPRI可读取高优先级数据
EPOLLRDHUP套接字对端关闭
EPOLLOUT普通数据可写
EPOLLET 采用边缘触发事件通知
EPOLLONESHOT 完成事件通知之后禁用检查
EPOLLERR 有错误发生
EPOLLHUP 出现挂断
  • EPOLLONESHOT 一旦描述符设置了该标志,epoll_wait只返回一次事件通知,然后将文件描述符标记为非激活状态,如果希望继续收到事件通知,需要使用epoll_ctl的EPOLL_CTL_MOD操作重新激活对这个文件描述符的检查,而不能使用EPOLL_CTL_ADD操作。

LT和ET模式

epoll有水平触发(LT)和边沿触发(ET)两种模式,默认的是水平触发。

  • 水平触发:有事件就绪时,epoll_wait会一直返回该事件直到该事件被处理
  • 边沿触发:有事件就绪时,epoll_wait只会返回一次,降低同一事件被重复触发的次数,效率比LT高。

要使用边沿触发模式,需要在调用epoll_ctl时在ev.events字段中指定EPOLLET标志。

ET模式下的文件描述符饥饿现象

当epoll工作在ET模式并监视多个文件描述符时,其中一个文件描述符有大量的输入存在,在该文件描述符处于就绪态后,我们尝试通过非阻塞式的读操作将所有的输入都读取,那么此时就会有其它处于就绪的文件描述符得不到处理的风险,而处于饥饿状态。

饥饿现象的解决方案

应用程序维护一个列表,列表中存放着已经被通知位就绪态的文件描述符,通过一个循环按照如下方式不断处理:

  1. 调用epoll_wait监视文件描述符,并将处于就绪状态的描述符添加到应用程序维护的列表中,如果这个文件描述符已经注册到应用程序维护列表中,那么监视的时间应该设为较小的值或者0,这样应用程序就可以迅速进行到下一步,去处理已经处于就绪态的文件描述符。

2、应用程序只在那些已经注册为就绪态文件描述符上进行一定限度的I/O操作,而不是每次epoll_wait调用后都从列表头开始处理,当相关的非阻塞I/O系统调用出现EAGAIN或EWOULDBLOCK错误时,文件描述符就可以从应用程序维护的列表中移除了。


作者:用户3541072051383
链接:https://juejin.cn/post/6926767244747735048

标签:文件,epoll,编程,列表,描述符,linux,就绪,wait
来源: https://blog.51cto.com/u_15169172/2710108

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有