前几天和同学一起讨论EPOLLONESHOT的作用,它的功能是这样的:

对于注册了EPOLLONESHOT事件的文件描述符,操作系统最多触发其上注册的包括可读,可写,错误中的一个,且只触发一次

刚一看感觉EPOLLONESHOT咋么就是ET模式相对于LT模式的区别,反复理解之后发现原来ET和ONESHOT的区别是ET只是可读可写或错误类的某一种事件类型只能被触发一次,而不同种类的事件类型却可以触发不止一次。难道仅仅是这个区别么,如果只是这样,我感觉给给事件类型加个ONESHOT还不如只用ET呢,好像这样也并没什么大问题。

又经过仔细读之后,我发现书上在介绍EPOLLONESHOT时说其是为了应对ET模式下同种事件可能会被触发多次的情况。这下我明白了ONESHOT的作用了,但是我却更加奇怪,ET模式下咋么会同种事件被触发多次呢? 
后来我想会不会是发送方发送的数据中由于一些原因导致其中的一部分和另一部分发送来的时间有很大(注意这个很大也不是很大,你懂得)的间隔.那么咋样才可能出现这种情况呢,当然你每次发送的数据越大出现这种几率的可能也就越大,所以为此我写了代码进行了测试,但是发现测了好多也没出现ET被触发多次的现象 
最后我想了下会不会是因为系统默认的接收缓冲区给的太大了?于是我将缓冲区改为500字节大小,然后send一次send100000数据,果不其然,这次ET模式下,可读被触发了40多次

具体测试情况如下: 
server端

#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<fcntl.h>
#include<sys/epoll.h>
#include<pthread.h>
using namespace std;#define MAX_EVENT_NUMBER 1024
#define BUFFER_SIZE 10
int SUM = 0;//设置文件描述符为非阻塞
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;}//添加fd到epoll内核事件表并选择是否开启ET模式
void addfd(int epoll_fd,int fd,bool enable_et)
{epoll_event event;event.data.fd = fd;event.events = EPOLLIN | EPOLLERR;if(enable_et){//开启et模式event.events |= EPOLLET;}epoll_ctl(epoll_fd,EPOLL_CTL_ADD,fd,&event);setnonblocking(fd);}//ET模式
void et(epoll_event *events,int number,int epollfd,int listenfd)
{char buf[BUFFER_SIZE];for(int i=0;i<number;i++){int sockfd = events[i].data.fd;if(sockfd == listenfd){struct sockaddr_in client_address;socklen_t client_addrlength = sizeof(client_address);int connfd = accept(listenfd,(struct sockaddr *)&client_address,&client_addrlength);//xiugaiint on = 500;//设置接收缓冲区大小为500setsockopt(connfd,SOL_SOCKET,SO_RCVBUF,(void *)&on,sizeof(int));addfd(epollfd,connfd,true);}else if(events[i].events & EPOLLIN){SUM++;while(1){bzero(buf,BUFFER_SIZE);int ret = recv(sockfd,buf,BUFFER_SIZE-1,0);if(ret < 0){//对于非阻塞I/O,下面条件成立表示数据已经全部读取完毕,此后epoll就能再一次触发sockfd上的EPOLLIN事件,以驱动下次读操作if((errno == EAGAIN) || (errno == EWOULDBLOCK)){cout<<"read later\n";break;}close(sockfd);break; }else if(ret == 0){close(sockfd);}else{cout<<"get "<<ret<<" bytes of content "<<buf<<endl;}    }cout<<"times:"<<SUM<<endl;}else{cout<<"something else happened\n";}}
}int main(int argc,char **argv)
{if(argc <= 2){cout<<"参数错误"<<endl;}char *ip = argv[1];int port = atoi(argv[2]);int ret = 0;struct sockaddr_in address;bzero(&address,sizeof(address));address.sin_family = AF_INET;inet_pton(AF_INET,ip,&address.sin_addr);address.sin_port = htons(port);int listenfd = socket(PF_INET,SOCK_STREAM,0);assert(listenfd >= 0);ret = bind(listenfd,(struct sockaddr *)&address,sizeof(address));assert(ret != -1);ret = listen(listenfd,5);assert(ret != -1);epoll_event events[MAX_EVENT_NUMBER];int epollfd = epoll_create(5);assert(epollfd != -1);addfd(epollfd,listenfd,true);while(1){int ret = epoll_wait(epollfd,events,MAX_EVENT_NUMBER,-1);if(ret < 0){cout<<"epoll failure"<<endl;break;}//使用et模式et(events,ret,epollfd,listenfd);}close(listenfd);return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161

client端

#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
int main(int argc,char **argv)
{if(argc <= 2){cout<<"您输入的参数有误";return 1;}char *ip = argv[1];int port = atoi(argv[2]);struct sockaddr_in server_address;bzero(&server_address,sizeof(server_address));server_address.sin_family = AF_INET;inet_pton(AF_INET,ip,&server_address.sin_addr);server_address.sin_port = htons(port);int sockfd = socket(PF_INET,SOCK_STREAM,0);assert(sockfd >= 0);if(connect(sockfd,(struct sockaddr *)&server_address,sizeof(server_address)) < 0){cout<<"error"<<endl;}else{string str1(100000,'a');int ret = send(sockfd,str1.c_str(),str1.size(),0);cout<<"ret"<<ret<<endl;}sleep(10);return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

服务器运行结果截图 

从图中可以看出EPOLLIN被触发了48次,所以我们就知道了EPOLL的ET模式会在接收缓冲区溢出时,可能发生被触发多次的情况

EPOLL在ET模式下会被触发多次么?相关推荐

  1. epoll在ET和LT模式下读写

    在一个非阻塞的socket上调用read/write函数, 返回EAGAIN或者EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 从字面上看, 意思是:EAGAIN: 再试一次, ...

  2. Epoll两种模式浅析(ET or LT)

    linux异步IO浅析  http://hi.baidu.com/_kouu/blog/item/e225f67b337841f42f73b341.html epoll有两种模式,Edge Trigg ...

  3. Epoll在LT和ET模式下的读写方式

    在一个非阻塞的socket上调用read/write函数,返回EAGAIN 或者 EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 从字面上看, 意思是:EAGAIN: 再试一次 ...

  4. C语言 epoll 工作模式之lt 等级触发 level trigger

    友链 // epoll的工作模式 // lt level trigger 水平触发模式 // et edge trigger 边缘触发 // lt模式是默认的 // et是高速工作方式 // 前者会一 ...

  5. C语言 epoll 工作模式之et 边缘触发 edge trigger

    友链 占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位 占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位占位 占位占位占位占位占位占位占位占位占位占 ...

  6. 取消Halcon连接相机在外触发模式下的超时时间

    取消Halcon连接相机在外触发模式下的超时时间 HALCON为大量的图像采集设备提供了接口,包括GenlCam,GigE和IIDC 1394,且支持众多品牌的相机.在日常的测试中,经常会利用halc ...

  7. 解决多进程模式下引起的“惊群”效应

    导语: 对不起,我是标题党,本文解决的不是我们理解的"惊群"效应,先为我们操作系统组的正下名,因为腾讯服务器的内核版本,已经解决epoll模式下的惊群现象(本文描述的现象跟惊群其实 ...

  8. (转)彻底学会使用epoll(一)——ET模式实现分析

    注:之前写过两篇关于epoll实现的文章,但是感觉懂得了实现原理并不一定会使用,所以又决定写这一系列文章,希望能够对epoll有比较清楚的认识.是请大家转载务必注明出处,算是对我劳动成果的一点点尊重吧 ...

  9. 彻底学会使用epoll(一)——ET模式实现分析

    注:之前写过两篇关于epoll实现的文章,但是感觉懂得了实现原理并不一定会使用,所以又决定写这一系列文章,希望能够对epoll有比较清楚的认识.是请大家转载务必注明出处,算是对我劳动成果的一点点尊重吧 ...

最新文章

  1. ICCV 2021审稿结果出炉,这里有一份Rebuttal写作指南
  2. 从创业公司到AI巨头 出门问问如何定义下一代人机交互?
  3. oracle的delete语句加速,Oracle delete语句调优一例
  4. 三维数组地址计算_科学计算NumPy
  5. python 面向对象之:反射,双下方法
  6. linux传输文件scp自动接密码,配置scp在Linux或Unix之间传输文件无需密码
  7. [XSY] 智慧树(线性同余方程组,线段树/树状数组)
  8. [Linux]消息队列
  9. Java中complex怎么被调用_java中存在三种调用机制
  10. 一个男生写的关于怎么追女生昨天没有说一个很关键的东西
  11. Linux 共享库LD_PRELOAD环境变量
  12. WiFi密码破解亦或是WiFi热点软件?
  13. Apple账号密码自动填充
  14. ts封装,H264和aac 封装成为ts,并生成m3u8
  15. 从docker 拉去指定版本的镜像
  16. 各种字符串Hash函数比较
  17. 如何识别手写汉字?跟着步骤就能完成
  18. k8s cpu 和内存资源说明
  19. Untiy添加水印并保存(包含文字转图片并打水印)
  20. Linux如何退出VI编辑

热门文章

  1. 内存超频会损坏内存吗 内存超频开不了机如何解决
  2. 日语中 に、で 用法总结
  3. android 输入法框架,Android输入系统(2)——输入系统框架(Android+Linux)
  4. 中国嵌入式模具封装市场趋势报告、技术动态创新及市场预测
  5. MAC 系统安装 Go 语言:从零开始搭建 Go 开发环境
  6. python还房贷_【开课吧python】全职妈妈用Python做出房贷计算系统
  7. 计算机一级公式乘积,使用Excel乘积函数,公式乘法和除法,指数的10例
  8. 物联网全栈教程--手把手教你开发一个智能浇花器(3)抽水电机PWM流速控制
  9. GEE水体提取之NDWI(矢量裁剪、统计面积、数据导出)
  10. android 激发亮度_如何使用有用的小脚本激发可怕的终端