epoll仅仅是一个异步事件的通知机制,其本身并不作任何的IO读写操作,它只负责告诉你是不是可以读或可以写了,而具体的读写操作,还要应用程序自己来完成。epoll仅提供这种机制是非常好的,它保持了事件通知与IO操作之间彼此的独立性,使得epoll的使用更加灵活。

接口介绍

int epoll_create(int size)

该函数生成一个epoll专用的文件描述符。它其实是在内核申请一空间,用来存放你想关注的fd上是否发生的事件。size就是你在这个epoll fd上能关注的最大fd数,这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

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

该函数用于控制某个epoll文件描述符上的事件,可以注册事件,修改事件,删除事件。

epfd:由 epoll_create生成的epoll专用的文件描述符;

op:要进行的操作例如注册事件,可能的取值:

1)EPOLL_CTL_ADD 注册新的fd到epfd中;

2)EPOLL_CTL_MOD修改已经注册的fd的监听事件;

3)EPOLL_CTL_DEL 从epfd中删除一个fd;

fd:需要监听的fd

event:指向epoll_event的指针,告诉内核需要监听的事件,常用的事件类型:

1)EPOLLIN :表示对应的文件描述符可以读;

2)EPOLLOUT:表示对应的文件描述符可以写;

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

4)EPOLLERR:表示对应的文件描述符发生错误;

5)EPOLLHUP:表示对应的文件描述符被挂断;

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

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

如果调用成功返回0,不成功返回-1

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

该函数用于轮询I/O事件的发生,如果发生则将发生的fd和事件类型放入到events数组中。 并且将注册在epfd上的fd的事件类型给清空,所以如果下一个循环你还要关注这个fd的话,则需要用epoll_ctl(epfd,EPOLL_CTL_MOD,fd,&ev)来重新设置fd的事件类型。这时不用EPOLL_CTL_ADD,因为fd并未清空,只是事件类型清空。

epfd:由epoll_create生成的epoll专用的文件描述符;

epoll_event:用于回传待处理事件的数组;

maxevents:每次能处理的事件数;

timeout:等待I/O事件发生的超时值,为0的时候表示马上返回,为-1的时候表示一直等下去,直到有事件返回。

epoll程序基本框架:

for( ; ; )

{

nfds = epoll_wait(epfd,events,20,500);

for(i=0;i

{

if(events[i].data.fd==listenfd) //有新的连接

{

connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); //accept这个连接

ev.data.fd=connfd;

ev.events=EPOLLIN|EPOLLET;

epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); //将新的fd添加到epoll的监听队列中

}

else if( events[i].events&EPOLLIN ) //接收到数据,读socket

{

n = read(sockfd, line, MAXLINE)) < 0 //读

ev.data.ptr = md; //md为自定义类型,添加数据

ev.events=EPOLLOUT|EPOLLET;

epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);//修改标识符,等待下一个循环时发送数据,异步处理的精髓

}

else if(events[i].events&EPOLLOUT) //有数据待发送,写socket

{

struct myepoll_data* md = (myepoll_data*)events[i].data.ptr; //取数据

sockfd = md->fd;

send( sockfd, md->ptr, strlen((char*)md->ptr), 0 ); //发送数据

ev.data.fd=sockfd;

ev.events=EPOLLIN|EPOLLET;

epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); //修改标识符,等待下一个循环时接收数据

}

else

{

//其他的处理

}

}

}

接口比较

Linux提供了select、poll、epoll接口来实现IO复用,三者的原型如下所示,本文从参数、实现、性能等方面对三者进行对比。

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

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

select的第一个参数nfds为fdset集合中最大描述符值加1,fdset是一个位数组,其大小限制为__FD_SETSIZE(1024),select的第二三四个参数表示需要关注读、写、错误事件的文件描述符位数组,这些参数既是输入参数也是输出参数,可能会被内核修改用于标示哪些描述符上发生了关注的事件。所以每次调用select前都需要重新初始化fdset。select对应于内核中的sys_select调用,sys_select首先将第二三四个参数指向的fd_set拷贝到内核,然后对每个被SET的描述符调用进行poll,并记录在临时结果中(fdset),如果有事件发生,select会将临时结果写到用户空间并返回;当轮询一遍后没有任何事件发生时,如果指定了超时时间,则select会睡眠到超时,睡眠结束后再进行一次轮询,并将临时结果写到用户空间,然后返回。select返回后,需要逐一检查关注的描述符是否被SET(事件是否发生)。

poll与select不同,通过一个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,pollfd中的events字段和revents分别用于标示关注的事件和发生的事件,故pollfd数组只需要被初始化一次。poll的实现机制与select类似,其对应内核中的sys_poll,只不过poll向内核传递pollfd数组,然后对pollfd中的每个描述符进行poll,相比处理fdset来说,poll效率更高。

epoll通过epoll_create创建一个用于epoll轮询的描述符,通过epoll_ctl添加/修改/删除事件,通过epoll_wait检查事件,epoll不是通过轮询,而是通过在等待的描述符上注册回调函数,当事件发生时,回调函数负责把发生的事件存储在就绪事件链表中,最后写到用户空间。epoll返回后,该参数指向的缓冲区中即为发生的事件,即epoll返回时已经明确的知道哪个fd发生了事件,不用再一个个比对。这样就提高了效率。同时select的FD_SETSIZE是有限止的,而epoll是没有限止的只与系统资源有关。epoll不会随着监听fd数目的增长而降低效率,因为select采用轮询方式,轮询的fd数目越多,自然耗时越多,而epoll是触发式的,所以效率高。

linux io端口复用,Linux系统IO复用接口(select、poll、epoll)相关推荐

  1. linux开启端口,linux配置端口,Linux关闭端口

    linux开启端口,linux配置端口,Linux关闭端口 开启端口 1.直接用命令开启端口开放端口命令----保存-----重启服务-------查看端口是否开放/sbin/iptables -I ...

  2. select poll epoll IO操作多路复用及猴子补丁

    一:select(能监控数量有限,不能告诉用户程序具体那个连接有数据) select目前几乎所有的平台都支持,其良好的跨平台支持也是一个优点 select的缺点在于单个进程能够监控的文件描述的数量存在 ...

  3. IO多路复用select,poll epoll以及区别

    看这个一次读懂 Select.Poll.Epoll IO复用技术 文章来简单理解下,如果不是很明白的话,可以参考下面转的知乎上面白话文列子 作者:Leslie 链接:https://www.zhihu ...

  4. select poll epoll 高效IO 多路转接

    目录 五种常见IO模型 高效IO的概念 阻塞 vs 非阻塞 非阻塞IO fcntl函数 I/O多路转接之select 初识select select函数原型 select操作接口 tcp_server ...

  5. Python之路-python(Queue队列、进程、Gevent协程、Select\Poll\Epoll异步IO与事件驱动)

    一.进程: 1.语法 2.进程间通讯 3.进程池 二.Gevent协程 三.Select\Poll\Epoll异步IO与事件驱动 一.进程: 1.语法 1 简单的启动线程语法 2 def run(na ...

  6. python3 异步 非阻塞 IO多路复用 select poll epoll 使用

    有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的. 下面记录下分别基于Select/Poll/Epoll的echo ser ...

  7. IO模型(select, poll, epoll的区别和原理)

    参考<unix网络编程> 参考http://blog.csdn.net/blueboy2000/article/details/4485874 参考http://blog.csdn.net ...

  8. IO多路复用select/poll/epoll详解以及在Python中的应用

    IO multiplexing(IO多路复用) IO多路复用,有些地方称之为event driven IO(事件驱动IO). 它的好处在于单个进程可以处理多个网络IO请求.select/epoll这两 ...

  9. Python异步非阻塞IO多路复用Select/Poll/Epoll使用

    来源:http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理 ...

  10. linux poll函数 实现,Linux select/poll/epoll 原理(一)实现基础

    本序列涉及的 Linux 源码都是基于 linux-4.14.143 . 1. 文件抽象 与 poll 操作 1.1 文件抽象 在 Linux 内核里,文件是一个抽象,设备是个文件,网络套接字也是个文 ...

最新文章

  1. 整型和浮点型的区别_C的基础内容:常量之数值型常量,适合新手的学习
  2. java.lang.InstantiationException 不能实例化某个对象
  3. python 批量更换图片格式脚本
  4. MySQL 中 AUTO_INCREMENT 的“坑”--id不连续
  5. C# WebBrowser自动填表与提交
  6. 前端学习(2192):Promise的all的使用
  7. php极差平级,平行志愿有级差吗志愿极差是什么
  8. java一行输入多个数据类型_Java中的3种输入方式实现解析
  9. 在老ASP中使用对象的对象生存期问题
  10. 计算机网络 Kurose 第二章 应用层 2.5 P2P文件分发 2.6 视频流和内容分发网
  11. 史上最全APP推广渠道,看看你最熟悉哪一种
  12. 中国已消失的 9 所世界级大学
  13. After Effects快捷键
  14. EDTA 最简易安装方法
  15. go每日新闻(2021-08-29)——Go程序内存假泄漏是怎么回事
  16. Tesseract综述
  17. 005永磁同步电机的数学模型:写了很久,非常适合零基础的同学学习参考
  18. phpsocket客户端以及服务器例子
  19. 实现将网页多条磁力链接一次性全部下载
  20. 室内外实时一体化建模

热门文章

  1. 13.2.8 用户认证
  2. 智宇科技 ZYARJX-1机械臂智能小车 —— PS2游戏手柄控制程序
  3. 征战蓝桥 —— 2013年第四届 —— C/C++A组第4题——颠倒的价牌
  4. PaddlePaddle训练营——公开课——AI核心技术掌握——第2章机器能“看”的现代技术
  5. 大数据互联网架构阶段 QuartZ定时任务+RabbitMQ消息队列
  6. 大数据WEB阶段(五)jQuery
  7. ubuntu 16.04 安装教程
  8. 【Linux网络编程】原始套接字编程
  9. 【Linux网络编程】无连接和面向连接协议的区别
  10. 如何制作linux系统硬盘,教你制作Linux操作系统的Boot/Root盘