1. 程式人生 > >EPOLL在ET模式下會被觸發多次麼?

EPOLL在ET模式下會被觸發多次麼?

前幾天和同學一起討論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); //xiugai int on = 500; //設定接收緩衝區大小為500 setsockopt(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; }

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;
}

伺服器執行結果截圖

從圖中可以看出EPOLLIN被觸發了48次,所以我們就知道了EPOLL的ET模式會在接收緩衝區溢位時,可能發生被觸發多次的情況

相關推薦

EPOLL在ET模式觸發

前幾天和同學一起討論EPOLLONESHOT的作用,它的功能是這樣的: 對於註冊了EPOLLONESHOT事件的檔案描述符,作業系統最多觸發其上註冊的包括可讀,可寫,錯誤中的一個,且只觸發一次 剛一看感覺EPOLLONESHOT咋麼就是ET模式相對於LT模

Flink window ReduceFunction 在一個事件到來的時候觸發

今天有一個同學在群裡面問了如下一個問題:“每輸入條記錄,都會立即執行四次。。”------因為一直都是用的event time + watermark的方式來做的流,不太清楚他這個情況。一度以為是事件被複制了多份,導致了視窗Function被觸發多次。後來看了一下原始碼,發現

jQuery 嵌套 event 觸發的原因

document button 鼠標 div 結果 rip multipl sub javascrip Html代碼如下: <div id="cover"> <input type="button" id="inside" value="submit

jQuery 巢狀 event 觸發的原因?

 最近,在公司做專案時,發現在click中巢狀click事件,會發生多次呼叫的問題,經過查詢相關資料 ,特整理。文中有參考https://segmentfault.com/q/1010000000458432等。 HTML程式碼: <div id="cover"&g

epoll用法說明,ET模式的邊緣觸發處理同時事件

#include <deque> #include <map> #include <vector> #include <pthread.h> #include <semaphore.h> #in

ubuntu 使用sudo apt-get update 出現 配置導致無法升級錯誤解決方法

code 開發機 goup 使用 lin logs 配置 周末 ubun 這個周六周末在考慮升級自己GPU開發機,在琢磨使用docker來按轉tensorflow環境,在升級軟件的時候爆出了如下錯誤 在 /etc/apt/sources.list.d/sogoupin

UITableViewStyleGrouped模式煩人的余間距

clas post idg ini rec head height 處理 one 第一個section上邊多余間距處理 // 隱藏UITableViewStyleGrouped上邊多余的間隔 _tableView.tableHeaderView = [[UIView all

解決一個特定的負載均衡定時任務執行的問題

nginx負載均衡 項目 post 緩存 日期 多少 size edi 開始 項目每天晚上有個定時任務,把redis緩存數據重新連接數據庫刷新一遍,耗時大約40分鐘。但問題是項目是nginx負載均衡,這個定時任務會執行多次。經過一些思考之後,用以下辦法解決: redis裏加

工作總結 頁面通過ajax 動態綁定 列表頁面 列表每一項的事件 事件觸發

什麽 就會 clas 方法調用 ack gpo 註冊 沒有 ajax 遇到一個問題 困惑了兩天 頁面的事件不知道為什麽觸發多次 試了各種辦法 對比了之前的頁面 各種測試 不是js css 外部鏈接 重復加載問題 也不是嵌套的 div 問題 各種都試過 最終發現 是

#JS 視窗resize避免觸發

window視窗改變時觸發resize,如何避免多次執行,設定一個300ms定時器即可。 //視窗變化監聽,避免resize多次執行卡頓 var resizeTimer = null; $(window).bind('resize', function () { if (resizeTi

Android程序app中Application回撥onCreate()方法執行分析及解決

最近工作中碰到一個問題,在優化app,使用DDMS檢視Application log過程中看到,app啟動了三個程序,一個主程序,兩個附帶的程序。如下圖可看到一個app啟動的三個程序。  自定義Application回撥方法onCreate()被執行了3次。開始不知是何原因。 相

IE複選框快速點選複選框狀態出現紊亂情況

複選框點選事件: <input type="checkbox" id="chk_2109_0" name="SFWSJ" kfdm="2109" onclick="setBNRJFProcess(this,2109);" > 在IE下連續多次點選,setBNRJFProces

static{}(即static塊),在類載入的時候執行且僅執行一,一般用來初始化靜態變數和呼叫靜態方法

這裡是一個工具類,因為連線配置資訊只需要執行一次就行所以採用static塊 static塊會最先執行 package com.my.jedis; import java.io.IOException; import java.io.InputStream; import

JVM中 一個類只載入一

     載入是相對於程序而言的,     啟動一個main方法,也就是啟動了一個程序,在一個程序中,一個類只會被載入一次public class TestThread { /**

JVM中 一個類只載入一

     載入是相對於程序而言的,      啟動一個main方法,也就是啟動了一個程序,在一個程序中,一個類只會被載入一次 public class TestThread { /** * 啟

echarts例項 動態更新 資料問題,點選事件觸發

function reloadTable() { var iii = layer.load(1, {shade: [0.1,'#fff'] });//提交的動畫 url = "change/query?selectType=" + $("#select

Caffe:CPU模式使用openblas-openmp(執行緒版本)

從所周知,所有的深度學習框架使用GPU執行是最快的,但是在不具備Nvidia顯示卡的環境下只使用CPU來執行,慢就慢點吧,對於學習階段還是夠用的。 Caffe用到的Blas可以選擇Altas,OpenBlas,Intel MKL,Blas承擔了大量了數學工作,

sudo apt-get update 時: 目標 Sources 在 /etc/apt/sources.list.d/source.list:配置

解決:cd /etc/apt/cources.list.d            rm  source.list 問題二         忽略:7 http://ppa.launchpad.net/noobslab/themes/ubuntu bionic InRelea

sui mobile 無限滾動時會觸發請求問題

首先,說問題之前,首先我們先看一下sui mobile 官網無限滾動的實現程式碼,(這裡主要是說底部無限滾動)。  官網中提到,要實現無限滾動,只需要“在可滾動的容器上新增“infinite-scroll”類,一般是頁面滾動區域 - div.content” 其中,

RadioGroup呼叫check(id)方法時,onCheckedChanged方法執行解決辦法

RadioGroup bottomMenuBar = (RadioGroup) findViewById(R.id.bottomMenuBar); bottomMenuBar.setOnCheckedChangeListener(this); bottomMenuBar.c