epoll监听文件_epoll使用详解

epoll介绍

epoll的行为与poll(2)相似,监视多个有IO事件的文件描述符。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

epoll_create(2) 创建一个新的epoll实例,并返回一个引用该实例的文件描述符

epoll_ctl(2) 创建epoll实例后,注册对感兴趣的文件描述符。当前注册在epoll实例上的文件描述符集被称为epoll集合。

epoll_wait(2) 等待I/O事件,如果当前没有事件可用,则阻塞调用线程。

水平触发和边沿触发

epoll事件分布接口既可以表现为边缘触发(ET),也可以表现为水平触发(LT)。这两种机制的区别

可以这样描述。假设有这种情况发生:

表示管道(rfd)的读侧的文件描述符在epoll实例上注册。

管道写入器在管道的写入端写入2 kB的数据。

调用epoll_wait(2)将返回rfd作为就绪文件描述符。

管道读取器从rfd读取1kb的数据。

epoll_wait(2)调用完成。

如果使用边缘触发标志将rfd文件描述符注册到epoll接口,那么第五步的epoll_wait(2)的调用可能会挂起,尽管文件输入缓冲区仍然有1kb数据可读;同时,远程对等端可能正在期望基于它已发送的数据的应答。这样做的原因是,只有在被监视文件描述符上发生更改时,边缘触发模式才交付事件。因此,在步骤5中,调用者可能会以等待那些仍在输入缓冲区中的数据的状态下结束。

在上面的例子中,将生成rfd上的一个事件,因为在2中完成了写入,而在3中使用了该事件。由于在4中完成的读操作不会消耗整个缓冲区数据,所以在步骤5中完成的对epoll_wait(2)的调用可能会无限期阻塞。

使用EPOLLET标志的应用程序应该使用非阻塞文件描述符,以避免在处理多个文件描述符时出现有阻塞的读写饥饿任务。建议使用epoll作为边沿触发(EPOLLET)接口的方式如下:

i、 具有非阻塞文件描述符

ii、只有在read(2)或write(2)返回EAGAIN后才等待事件。

相反,当EPOLLET作为水平触发接口使用时(默认情况下,没有指定EPOLLET), epoll只是一个更快的poll(2),并且可以在使用后者的任何地方使用,因为它具有相同的语义。

Epoll的优点:

1、支持一个进程打开大数目的socket描述符(FD)

select能打开的文件描述符有一定的限制,FD_SETSIZE设置,默认值是2048,有两种解决方法,1、修改它的值,然后重新编译内核。2、使用多进程加入要并发20w个客户,那么就要开100进程;epoll则没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是2万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。

2、IO效率不随FD数目增加而线性下降

select/poll采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;内核 / 用户空间内存拷贝问题,select/poll需要复制大量的句柄数据结构,产生巨大的开销;select/poll返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件,导致效率呈现线性下降。但是epoll不存在这个问题,它只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。

3、支持边缘触发模式

select/poll的触发方式是水平触发,应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select/poll调用还是会将这些文件描述符通知进程。

4、使用mmap加速内核与用户空间的消息传递。

select/poll和epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝很重要,在这点上,select/poll需要复制整个FD数组,产生巨大的开销;而epoll是通过内核于用户空间mmap同一块内存实现的。

epoll的系统调用

epoll_create

int epoll_create(int size);

int epoll_create1(int flags);

创建一个epoll的句柄。自从linux2.6.8之后,size参数是被忽略的,更推荐使用epoll_crete1(0)来替代,flags可以设置EPOLL_CLOEXEC标志

epoll_ctl

#include

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

该系统调用对文件描述符epfd引用的epoll(7)实例执行控制操作。它请求对目标文件描述符fd执行操作op。

epfd : epoll_create创建的文件描述符.

op :参数的有效参数为:

EPOLL_CTL_ADD

在文件描述符epfd引用的epoll实例上注册目标文件描述符fd。

EPOLL_CTL_MOD

修改已注册描述符fd关联的事件。

EPOLL_CTL_DEL

从epfd引用的epoll实例中删除(取消注册)目标文件描述符fd。该事件将被忽略,并且可以是NULL

fd :待监听的fd

epoll_event : 描述链接到文件描述符fd的对象,它的定义如下

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 */

};

events成员是由以下可用事件类型的零个或多个组合在一起组成的位掩码:

EPOLLIN :关联的文件描述符可以读(包括对端SOCKET正常关闭);

EPOLLOUT:关联的文件描述符可以写;

EPOLLPRI:关联的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);

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

EPOLLHUP:关联的文件描述符被挂断;

EPOLLRDHUP:流套接字对等关闭连接,或半关闭写。(当使用边缘触发监视时,此标记对于编写简单代码检测对等端是否关闭特别有用。2.6.17引入)

EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。

EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个fd的话,需要再次把这个fd加入到EPOLL队列里

它们在内核头文件里的定义如下:

33

34 enum EPOLL_EVENTS

35 {

36 EPOLLIN = 0x001,

37 #define EPOLLIN EPOLLIN

38 EPOLLPRI = 0x002,

39 #define EPOLLPRI EPOLLPRI

40 EPOLLOUT = 0x004,

41 #define EPOLLOUT EPOLLOUT

42 EPOLLRDNORM = 0x040,

43 #define EPOLLRDNORM EPOLLRDNORM

44 EPOLLRDBAND = 0x080,

45 #define EPOLLRDBAND EPOLLRDBAND

46 EPOLLWRNORM = 0x100,

47 #define EPOLLWRNORM EPOLLWRNORM

48 EPOLLWRBAND = 0x200,

49 #define EPOLLWRBAND EPOLLWRBAND

50 EPOLLMSG = 0x400,

51 #define EPOLLMSG EPOLLMSG

52 EPOLLERR = 0x008,

53 #define EPOLLERR EPOLLERR

54 EPOLLHUP = 0x010,

55 #define EPOLLHUP EPOLLHUP

56 EPOLLRDHUP = 0x2000,

57 #define EPOLLRDHUP EPOLLRDHUP

58 EPOLLEXCLUSIVE = 1u << 28,

59 #define EPOLLEXCLUSIVE EPOLLEXCLUSIVE

60 EPOLLWAKEUP = 1u << 29,

61 #define EPOLLWAKEUP EPOLLWAKEUP

62 EPOLLONESHOT = 1u << 30,

63 #define EPOLLONESHOT EPOLLONESHOT

64 EPOLLET = 1u << 31

65 #define EPOLLET EPOLLET

66 };

67

68

69 /* Valid opcodes ( "op" parameter ) to issue to epoll_ctl(). */

70 #define EPOLL_CTL_ADD 1 /* Add a file descriptor to the interface. */

71 #define EPOLL_CTL_DEL 2 /* Remove a file descriptor from the interface. */

72 #define EPOLL_CTL_MOD 3 /* Change file descriptor epoll_event structure. */

epoll_wait

#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);

等待在epoll监控的事件中已经发生的事件。

epfd : epoll_create() 的返回值.

events : 分配好的epoll_event结构体数组,epoll将会把发生的事件赋值到events数组中(events不可以是空指针,内核只负责把数据复制到这个events数组中,不会去帮助我们在用户态中分配内存)

maxevents : maxevents告知内核这个events有多大,这个 maxevents的值大于0(否则Error :Invalid argument)

timeout : 超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。如果函数调用成功,返回对应I/O上已准备好的文件描述符数目,如返回0表示已超时,它会阻塞直到

一个文件描述符有事件发生;

信号处理器中断;

超时;

epoll示例程序

此程序简单测试一下三个API,注册标准输出的描述符到epoll,监视标准输出的读事件,触发后回显一遍,quit退出程序.

#include

#include

#include

#include

#include

#include

#include

#include

#include

typedef std::vector PollFdList;

int main(int argc ,char **argv)

{

int fd;

char buf[1024];

int i,res,real_read, maxfd;

if((fd=open("/dev/stdin",O_RDONLY|O_NONBLOCK)) < 0)

{

fprintf(stderr,"open data1 error:%s",strerror(errno));

return 1;

}

PollFdList m_pollfds;

int epfd = epoll_create1(EPOLL_CLOEXEC);

struct epoll_event ev;

ev.events = EPOLLIN | EPOLLPRI;

ev.data.fd = fd;

epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

m_pollfds.resize(1024);

while(1)

{

int ret = epoll_wait(epfd, m_pollfds.data(), m_pollfds.size(), 5000);

if (ret < 0)

{

printf("ePoll error : %s\n",strerror(errno));

return 1;

}

if(ret == 0){

printf("ePoll timeout\n");

continue;

}

for (i = 0; i< 1; i++)

{

if (m_pollfds[i].events & EPOLLIN)

{

memset(buf, 0, 1024);

real_read = read(m_pollfds[i].data.fd, buf, 1024);

if (real_read < 0)

{

if (errno != EAGAIN)

{

printf("read eror : %s\n",strerror(errno));

continue;

}

}

else if (!real_read)

{

close(m_pollfds[i].data.fd);

m_pollfds[i].events = 0;

}

else

{

if (i == 0)

{

buf[real_read] = '\0';

printf("%s", buf);

if ((buf[0] == 'q') || (buf[0] == 'Q'))

{

printf("quit\n");

return 1;

}

}

else

{

buf[real_read] = '\0';

printf("%s", buf);

}

}

}

}

}

exit(0);

}

./test

hello

hello

hello epoll

hello epoll

ePoll timeout

quit

quit

quit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IDL学习:语法基础-结构体

结构体是由一批数据组合而成的结构型数据。组成结构型数据的每个数据称为结构型数据的“属性”&#xff08;亦称之为“成员”&#xff09;&#xff0c;这些成员可以是变量、数组、字符串以及结构等类型数据。IDL中常用于函数返回值&#xff08;PS&#xff1a;因为IDL中函数最多…

hdfs数据节点分发什么协议_分布式文件系统HDFS解析

Hadoop 主要由HDFS和MapReduce 引擎两部分组成。最底部是HDFS&#xff0c;它存储Hadoop 集群中所有存储节点上的文件。HDFS 的上一层是MapReduce 引擎&#xff0c;该引擎由JobTrackers 和TaskTrackers组成。一、HDFS基本概念1、数据块HDFS默认的最基本的存储单位是64M的数据块&…

IDL学习:语法基础-指针、链表

本博客将介绍IDL语法基础中的指针、链表的创建及相关的用法。记录自己的学习整理理解 。 1. 指针 指针也就是内存地址&#xff0c;是用来存放内存地址的变量&#xff0c;指针可以理解为通讯地址&#xff0c;可以通过通讯地址查询具体的信息&#xff0c;而指针可以查询所指向的…

计算机等级考试java题型_计算机二级考试《java》试题及答案

计算机二级考试《java》试题及答案2017下半年计算机二级考试将于9月23日-26日举行&#xff0c;下面是小编为大家整理的计算机二级考试《java》试题及答案&#xff0c;欢迎参考~计算机二级考试《java》试题及答案一、判断题1. Java语言中的数组元素下标总是从0开始&#xff0c;下…

IDL学习:语法基础-对象、哈希表

本博客将介绍IDL语法基础中的对象、哈希表的创建及相关的操作发法。哈希表、链表都可以看做对象&#xff0c;包含了add、reserve、Sort等方法。记录自己的学习整理理解 。 1. 对象 对象是数据&#xff08;属性&#xff09;和程序&#xff08;方法&#xff09;封装在一起的实体…

hdfs中8031是什么端口号_在宿主机如何访问docker中hadoop的hdfs:ip:9000啊, 端口映射出来啊...

本人有一个3节点hadoop, 启动了3个docker容器, 众所周知, docker容器内服务的端口是可以映射到宿主机的端口的, 我采用-P将容器的所有端口映射到主机端口, 命令如下:docker run -it -v /Users/yc/hadoop/docker:/test -P -h h1 --name h1 sequenceiq/hadoop-docker /etc/bootst…

linux nginx安启动_linux下nginx编译安装启动

1、在指定目录解压包命令&#xff1a;tar -zxvf nginx-1.10.3.tar.gz解压后&#xff0c;在nginx-1.10.3同级目录下&#xff0c;创建nginx目录(编译安装目录)2、编译安装nginx是需要编译安装&#xff0c;在nginx-1.10.3目录下执行命令命令&#xff1a; ./configure --prefix/usr…

linux怎样自制库_如何制作自己的LINUX系统?

创建工作目录使用busybox生成根文件系统中的bin等目录创建服务启动脚本与inittab文件与fstab文件创建根文件系统的init脚本(initrc使用linuxrc&#xff0c;而initramfs使用init脚本&#xff0c;所以先删除busybox为initrc生成的默认的linuxrc文件&#xff0c;rm-rf$LINUX/linux…

茶苑机器人怎么看出来_小儿脑瘫怎么看出来?出现4个异常,该早点去看医生...

小儿脑瘫表现出来的症状是多种多样的&#xff0c;一般儿童三个月就能够展现出来&#xff0c;家长应该多观察孩子的一些异常情况&#xff0c;及时去医院做诊断&#xff0c;做到防患于未然。小儿脑瘫的表现有哪些&#xff1f;1、运动发育明显落后正常的儿童3个月能抬头&#xff0…

itil 容量管理流程_探索ITIL和DevOps的边界

其实在今天的运维领域&#xff0c;ITIL和DevOps之间的冲突还是蛮明显的&#xff0c;有些是表现在产品上&#xff0c;有些是表现在思维/理念上。ITIL在产品上以流程为核心目标的设计&#xff0c;很难满足自动化的要求&#xff0c;DevOps极力推崇工具/平台/自服务文化&#xff1b…

本博客IDL 学习目录

本博客非技术博客&#xff0c;而是总结我在学习IDL、编写IDL代码方面的博客&#xff0c;旨在方便各位可以通过我这篇博客直接选感兴趣的部分。本博客将会持续更新&#xff0c;不断补充…… IDL 学习 1. IDL 文本编码、代码补全快捷方式、IDL doc、格式器、行号显示设置 2. ID…

python中一个汉字是几个字节_数据库中汉字是几个字节

不依赖微软的库和WindowsAPI&#xff0c;没能试验成功&#xff01;######问题已解决&#xff0c;谢谢。######看这篇文章&#xff0c;讲的很清楚(&#xff1a;)这是从其他地方拷贝过来的) UNICODE环境设置 在安装Visual Studio时&#xff0c;在选择VC时需要加入unicode选项&…

Matlab 中@ 的用法

Matlab 中的用法主要有&#xff1a;函数句柄、函数表达式、调用父类以及类文件夹。 前两种有很多介绍&#xff0c;后两种涉及类&#xff0c;介绍的人很少。前2个例子&#xff0c;参考了其它博客&#xff0c;总感觉用法都写的不全&#xff0c;所以在此基础上&#xff0c;补充了3…

金蝶k3单据编码规则_金蝶K3存货跌价案例教程

目录案例介绍 后台设置 计提存货跌价准备显示计提表计提凭证模板设置计提凭证生成手工结转跌价准备案例介绍关于存货跌价准备&#xff0c;企业会计准则第1号存货相关规定如下&#xff1a;第十五条 资产负债表日&#xff0c;存货应当按照成本与可变现净值孰低计量。存货成本高于…

maven 关联源码插件_繁琐的任务简单化,Maven的插件机制

Maven的生命周期与Maven插件是项目绑定的&#xff0c;生命周期可以理解为项目构建步骤的集合&#xff0c;它定义了各个构建环节的执行顺序&#xff0c;有了这个顺序&#xff0c;Maven 就可以自动化的执行构建命令。Maven 的核心程序中定义了抽象的生命周期&#xff0c;生命周期…

php配置email支持_配置以及实现mail()函数

配置sendmail.ini文件error_logfileerror.log; create debug log as debug.log (defaults to same directory as sendmail.exe); uncomment to enable debuggingdebug_logfiledebug.log; if your smtp server requires authentication, modify the following two linesauth_use…

树莓派控制电机转速_怎样用树莓派控制直流电机的方向和速度

步骤1&#xff1a;DC的控制方向通过RPi电机使用RPi控制直流电机我们的下一个任务是使用树莓派上的python脚本和GPIO头控制直流电动机&#xff0c;这将在我们的脑海中产生一幅“机器人如何工作”的图景。您可以根据外面的天气来控制房间的风扇(因为您知道rpi会使用传感器)。完成…

双稳态继电器工作原理图_固态继电器只有单一的作用吗?带你了解不一样的固态继电器...

固态继电器简写SSR(Solid State Relay)&#xff0c;是一种全部又分离的固态电子元件(如光耦合器、晶体管、可控硅、电阻、电容、集成电路等)组成的无触点电阻开关&#xff0c;这里请注意&#xff0c;相比较与继电器、接触器&#xff0c;固态继电器是无触点的耦合开关。因此&…

c++switch实现猜拳_C语言实现人机猜拳游戏,非常适合C++小白练习的项目!

学习迷茫遇到问题了吗&#xff1f;现在关注微信公众号&#xff1a;C程序编程 免费获取进阶指导和学习资料&#xff01;本文福利在文末&#xff01;这是一个简单的猜拳游戏&#xff08;剪子包子锤&#xff09;&#xff0c;让你与电脑对决。你出的拳头由你自己决定&#xff0c;电…

bootstraptable获得所有行_2020广汽本田安全中国行·首届道路安全创新大赛成功举办...

两辆汽车分别搭载了代表着婴儿的红心&#xff0c;当两车相撞&#xff0c;被安全座椅包裹的红心安然无恙&#xff0c;而另一颗没有安全措施的红心直接裂开。画面配文"救救孩子"&#xff0c;让人格外揪心。这是来自2020年广汽本田安全中国行首届道路安全创新大赛公益广…