I/O复用之 epoll

epoll 系统调用


1. 内核事件表

epoll使用一系列函数来完成任务,把用户关心的文件描述符中的事件放到内核里的一个事件表中,因此不用像select、poll那样每次调用都要重复传入文件描述符集或事件表。epoll需要一个文件描述符来唯一标识该事件表,该文件描述符使用epoll_create函数创建:

    #include <sys/epoll.h>int epoll_create( int size );

size 标记事件表大小。该函数返回的文件描述符将用作其他所有epoll系统调用的第一个参数,以指定要访问的内核事件表。

epoll_ctl函数用于操作epoll的内核事件表:

    #include <sys/epoll.h>int epoll_ctl( int epfd, int op, int fd, struct epoll_event * event )

fd参数是要操作的文件描述符,op参数指定操作类型(如下):

  • EPOLL_CTL_ADD,往事件表中注册fd上的事件
  • EPOLL_CTL_DEL,删除fd上的注册事件
  • EPOLL_CTL_MOD,修改fd上的注册事件

event参数指定被操作的事件,它是epoll_event结构类型指针。epoll_event的定义如下:

    struct epoll_event{__uint32_t events;  //epoll事件epoll_data_t data;  //用户数据}

其中events成员描述事件类型(如 EPOLLIN表示数据可读事件)。epoll_data_t 定义如下:

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

epoll_data_t 是一个共用体,其4个成员使用最多的是fd,它指定事件所从属的目标文件描述符。各成员不能同时使用。


2. epoll_wait 函数

epoll_wait 函数在一段超时时间内等待一组文件描述符上的事件,其原型如下:

#include <sys/epoll.h>
int epoll_wait( int epfd, struct epoll_event * events, int maxevents, int timeout ) 

该函数成功时返回就绪的文件描述符的个数,失败时返回-1并设置errno。timeout参数为延时时间。maxevents参数指定最多监听多少个事件,它必须大于0。
epoll_wait函数如果检测到事件,就将所有就绪的事件从内核事件表(由epfd指定)中复制到它的第二个参数events指向的数组,该数组只用于输出epoll_wait检测到的就绪事件,而不像select和poll那样既传入用户注册事件,又输出内核检测到的就绪事件。这极大提高了应用程序索引就绪文件描述符的效率。

    /* 如何索引 epoll 返回的就绪文件描述符 */int ret = epol_wait( epoll_fd, events, MAX_EVENT_NUMBER, -1 );// 仅遍历就绪的ret个文件描述符for ( int i = 0; i < ret; i++ ){int sock_fd = events[i].data.fd;  //events中的所有文件描述符都已就绪handle( sock_fd );  //处理就绪的sock_fd}

3. LT和ET模式

LT : 电平触发(默认工作方式)
ET :边沿触发(高效工作方式)

对于采用LT工作模式的文件描述符,当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序可以不立即处理该事件。这样,当下一次调用epoll_wait()时,epoll_wait()还会再次向应用程序通知此事件,直至该事件被处理。
对于采用ET工作模式的文件描述符,当epoll_wait检测到其上有事件发生并将此事件通知应用程序后,应用程序必须立即处理该事件,因为后续的epoll_wait()将不再向应用程序通知该事件。
可见,ET模式在很大程度上降低了同一个epoll事件被重复触发的次数,因此效率会比LT模式高。


4. code

/*  该程序以  “ ./a.out ip_number port_number ”   方式使用
**  通过telnet连接到该运行程序 */#include <iostream>
#include <cstdio>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <sys/epoll.h>
using namespace std;const int MAX_EVENT_NUMBER = 1024;
const int BUFFER_SIZE = 10;void err( int );
void addfd( int , int , bool );
int setnonblocking( int );
void lt( epoll_event * , int , int , int );
void et( epoll_event * , int , int , int );int main(int argc, char * argv[]) {if ( argc < 3 ) {cout << "usage:\n";return 1;}const char *ip = argv[1];const int port = atoi( argv[2] );struct sockaddr_in address;memset( &address, 0, sizeof( address ) );address.sin_family = AF_INET;address.sin_port = htons( port );inet_pton( AF_INET, ip, &address.sin_addr );int sock_fd = socket( AF_INET, SOCK_STREAM, 0 );if ( sock_fd < 0) {err( __LINE__ );}int ret = bind( sock_fd, ( struct sockaddr * )&address, sizeof( address ) );if ( ret < 0 ) {err( __LINE__ );}ret = listen( sock_fd, 5 );if ( ret < 0 ) {err( __LINE__ );}epoll_event events[MAX_EVENT_NUMBER];  //内核事件表,通过epoll_wait()函数发生作用int epoll_fd = epoll_create( 5 );if ( epoll_fd < 0 ) {err( __LINE__ );}addfd( epoll_fd, sock_fd, true );while( true ) {ret = epoll_wait( epoll_fd, events, MAX_EVENT_NUMBER, -1 );if ( ret < 0 ) {cout << "epoll failure\n";break;}lt( events, ret, epoll_fd, sock_fd );  //使用LT模式// et( events, ret, epoll_fd, sock_fd );  //使用ET模式}close( sock_fd );return 0;
}void err(int line) {cout << "error: line " << line << endl;
}void addfd( int epoll_fd, int fd, bool enable_et ) {epoll_event event;event.data.fd = fd;event.events = EPOLLIN;if ( enable_et ) {event.events |= EPOLLET;}epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &event );setnonblocking( fd );
}int setnonblocking( int fd ) {int old_option = fcntl( fd, F_GETFL );int new_option = old_option | O_NONBLOCK;fcntl( fd, F_SETFL, new_option );return old_option;
}void lt( epoll_event * events, int number, int epoll_fd, int listen_fd) {char buf[ BUFFER_SIZE ];for( int i = 0; i < number; i++ ) {int sock_fd = events[i].data.fd;if ( sock_fd == listen_fd ) {  //有新的连接请求struct sockaddr_in client;socklen_t client_length = sizeof( client );int conn_fd = accept( sock_fd, ( struct sockaddr * )&client,&client_length );addfd( epoll_fd, conn_fd, false );} else if ( events[i].events & EPOLLIN ) {  //还存在未读数据cout << "event trigger once\n";memset( buf, 0, sizeof( buf ) );int ret = recv( sock_fd, buf, BUFFER_SIZE - 1, 0 );if ( ret <= 0 ) {close( sock_fd );}printf( "get %d bytes of content: -%s-\n", ret, buf );} else {cout << "something else happened\n";}}
}void et( epoll_event * events, int number, int epoll_fd, int listen_fd) {char buf[ BUFFER_SIZE ];for ( int i = 0; i < number; i++ ) {int sock_fd = events[i].data.fd;if ( sock_fd == listen_fd ) {  //有新的连接请求struct sockaddr_in client;socklen_t client_length = sizeof( client );int conn_fd = accept( sock_fd, ( struct sockaddr * )&client,&client_length );addfd( epoll_fd, conn_fd, true );} else if ( events[i].events & EPOLLIN ) {  //还存在未读数据printf("event trigger once\n");while( true ) {memset( buf, 0, sizeof( buf ) );int ret = recv( sock_fd, buf, BUFFER_SIZE - 1, 0 );if ( ret < 0 ) {/* 数据已全部读取完毕 */if ( errno == EAGAIN || errno == EWOULDBLOCK ) {cout << "read later\n";break;}close( sock_fd );break;} else if ( !ret ) {close( sock_fd );} else {printf("got %d bytes of content: -%s-\n", ret, buf);}}}}
}

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

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

相关文章

uva 1153—— Keep the Customer Satisfied

题意&#xff1a;有n个工作&#xff0c;已知每个工作的开始时间和结束时间&#xff0c;问最多能完成多少工作。 思路&#xff1a;贪心。要想使得最后的结果最佳&#xff0c;那么开始的晚的&#xff0c;要在最后来做。在此基础上&#xff0c;需要保证先做开始的早的&#xff08;…

I/O复用之 EPOLLONESHOT 事件

EPOLLONESHOT 事件 EPOLLONESHOT 事件 1. 使用EPOLLONESHOT的原因及优点2. recv返回值 及 与errno的配合使用3. 示例程序 1. 使用EPOLLONESHOT的原因及优点 即使使用ET模式&#xff0c;一个socket上的某个事件还是可能被触发多次。比如&#xff1a;一个线程在读取完某个sock…

uva 1612——Guess

题意&#xff1a;有n个选手参加比赛&#xff0c;比赛有3个题目&#xff0c;每个选手每个题目都有一个评测之前的于得分&#xff0c;当通过题目时才可以得到相应分数&#xff0c;否则为0&#xff0c;然后按照得分排名&#xff0c;id小的排在前面&#xff0c;现在给定选手的于得分…

uva 1611——Crane

题意&#xff1a;给定一个1-n的排序&#xff0c;每次可以选定一个偶数长的序列&#xff0c;然后交换前一部分和后一部分&#xff0c;使得最后的成为1-n的序列。求最后的次数和每次的策略。 思路&#xff1a;贪心。每次贪心的策略都是把i放到第i位置上&#xff0c;交换的时候找到…

【世界上最美丽的7张太阳照片】

【世界上最美丽的&#xff17;张太阳照片】 文章来源:http://ms.blogger.cn/peon/posts/1634.aspx转载于:https://www.cnblogs.com/paulzhu/archive/2004/02/24/1572.html

uva 11925——Generating Permutations

题意&#xff1a;给定一个1-n的排列&#xff0c;用不超过2*n2的操作把他变成升序。每次操作只有两种&#xff0c;一种是交换前两个元素&#xff0c;另外一种是把最后一个元素放到最后一位。 思路&#xff1a;贪心。用双端队列来保存数据&#xff0c;每次当v[0]>v[1]&&am…

二维map —— HDU1263

水果 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 8752 Accepted Submission(s): 3482Problem Description 夏天来了~~好开心啊,呵呵,好多好多水果~~ Joe经营着一个不大的水果店.他认为生存之道就是经营最…

uva 11491——Erasing and Winning

题意&#xff1a;给定一个n位的整数&#xff0c;要求从中去掉k位&#xff0c;使得剩下的数字最大。 思路&#xff1a;单调队列。在满足删除的数等于k 的前提下求一个不敌减的序列。 code&#xff1a; #include <iostream> #include <cstdio> #include <cmath>…

工作组和域的区别

局域网上的资源需要管理&#xff0c;“域”和“工作组”就是两种不同的网络资源管理模式。那么二者有何区别呢&#xff1f;看了这篇文章&#xff0c;您就会明白了。工作组 Work Group在一个网络内&#xff0c;可能有成百上千台电脑&#xff0c;如果这些电脑不进行分组&#xff…

uva 12545——Bits Equalizer

题意&#xff1a;给定两个等长的串s和t&#xff0c;其中s串包括0&#xff0c;1&#xff0c;&#xff1f;&#xff0c;T包含0&#xff0c;1&#xff0c;每次可以把s中的0变成1或者交换任意两个数或者&#xff1f;变成任意01.求由s到t的最小步数。 思路&#xff1a;杂。所有带&am…

Ananagrams Uva 156

Ananagrams (map的使用) Most crossword puzzle fans are used to anagrams–groups of words with the same letters in different orders–for example OPTS, SPOT, STOP, POTS and POST. Some words however do not have this attribute, no matter how you rearrange their…

流星

我的心情像下雨故乱飞溅 静落一地因为没有你 我的心情像流星划破天际 惨淡的光阴因为没有你 我的心情像风铃没有主见 无法成形因为没有你 我的心情像问号钩子心碎 一点茫然因为没有你 我的心情像冰块没有温度 化了一地因为没有你 我好想你我好想你我好想你 http://photo.…

uva 1623——Enter The Dragon

题意&#xff1a;有n个装满水的湖&#xff0c;可以预知将来m天下雨情况&#xff0c;每次下满一个湖&#xff0c;或者不下&#xff0c;不下雨的时候可以让某个湖变干&#xff0c;问是否存在一种方案使得每次下雨之前湖总是干的。 思路&#xff1a;贪心。什么时候下雨&#xff0c…

CodeForce 2A —— Winner

A. Winner The winner of the card game popular in Berland “Berlogging” is determined according to the following rules. If at the end of the game there is only one player with the maximum number of points, he is the winner. The situation becomes more diffi…

GARFIELD@12-30-2004

tele-murderer 转载于:https://www.cnblogs.com/rexhost/archive/2004/12/30/84230.html

[codevs] 1098 均分纸牌

均分纸牌 题目描述 Description 有 N 堆纸牌&#xff0c;编号分别为 1&#xff0c;2&#xff0c;…, N。每堆上有若干张&#xff0c;但纸牌总数必为 N 的倍数。可以在任一堆上取若于张纸牌&#xff0c;然后移动。   移牌规则为&#xff1a;在编号为 1 堆上取的纸牌&#xf…

uva 11536——Smallest Sub-Array

题意&#xff1a;给定n个数&#xff0c;这n个数在m的范围之内。v[i](v[i-1]v[i-2]v[i-3])%m1; 然后求一个最短连续子序列使得序列内包括1-k个数。 思路&#xff1a;枚举。枚举以v[i]结尾的最短序列。用ct维护已经找到的k个数中的个数&#xff0c;queue跳转区间。 code&#x…

好消息,关于2005的default provider

好消息&#xff0c;关于2005的default provider 看到一则消息&#xff0c;说在vs.net 2005 bETA 2以后&#xff0c;关于Membership, Roles, Profile and Personalization 的会默认使用 SQL SERVER 2005的provider(现在BETA 1使用的是ACCESS&#xff0c;所以在做MEMBERSHIP&…

[Qt] 解决toggled无法触发setVisible

解决toggled无法触发setVisible 解决方法&#xff1a; 在QT Designer中&#xff0c;创建QPushButton时需要将按钮修改为checkable。在默认情况下&#xff0c;checkable是不选中的&#xff0c;默认为触发按钮&#xff08;trigger button&#xff09;&#xff0c;也就是按下之后…

周华健,歌声伴我成长(四)

1997年&#xff0c;经典的朋友《朋友》 朋友 这些年一个人 风也过雨也走 有过泪有过错 还记得坚持甚麽 真爱过才会懂 会寂寞会回首 终有梦终有你在心中 朋友一生一起走 那些日子不再有 一句话一辈子 一生情一杯酒 朋友不曾孤单过 一声朋友你会懂 还有伤还有痛 还要走还有我 199…