網編 17 epoll條件 水平 觸發和邊緣觸發

2021-09-16 19:29:37 字數 4847 閱讀 6049

epoll也是實現i/o多路復用的一種方法,為了深入了解epoll的原理,我們先來看下epoll水平觸發(level trigger,lt,lt為epoll的預設工作模式)與邊緣觸發(edge trigger,et)兩種工作模式。

使用脈衝訊號來解釋lt和et可能更加貼切。level是指訊號只需要處於水平,就一直會觸發;而edge則是指訊號為上公升沿或者下降沿時觸發。說得還有點玄乎,我們以生活中的乙個例子來模擬lt和et是如何確定讀操作是否就緒的。

水平觸發 

兒子:媽媽,我收到了500元的壓歲錢。 

媽媽:嗯,省著點花。 

兒子:媽媽,我今天花了200元買了個變形金剛。 

媽媽:以後不要亂花錢。 

兒子:媽媽,我今天買了好多好吃的,還剩下100元。 

媽媽:用完了這些錢,我可不會再給你錢了。 

兒子:媽媽,那100元我沒花,我攢起來了 

媽媽:這才是明智的做法! 

兒子:媽媽,那100元我還沒花,我還有錢的。 

媽媽:嗯,繼續保持。 

兒子:媽媽,我還有100元錢。 

媽媽:…

接下來的情形就是沒完沒了了:只要兒子一直有錢,他就一直會向他的媽媽匯報。lt模式下,只要核心緩衝區中還有未讀資料,就會一直返回描述符的就緒狀態,即不斷地喚醒應用程序。在上面的例子中,兒子是緩衝區,錢是資料,媽媽則是應用程序了解兒子的壓歲錢狀況(讀操作)。

邊緣觸發 

兒子:媽媽,我收到了500元的壓歲錢。 

媽媽:嗯,省著點花。 

(兒子使用壓歲錢購買了變形金剛和零食。) 

兒子: 

媽媽:兒子你倒是說話啊?壓歲錢呢?

這個就是et模式,兒子只在第一次收到壓歲錢時通知媽媽,接下來兒子怎麼把壓歲錢花掉並沒有通知媽媽。即兒子從沒錢變成有錢,需要通知媽媽,接下來錢變少了,則不會再通知媽媽了。在et模式下, 緩衝區從不可讀變成可讀,會喚醒應用程序,緩衝區資料變少的情況,則不會再喚醒應用程序。

我們再詳細說明lt和et兩種模式下對讀寫操作是否就緒的判斷。

條件觸發:

只要輸入緩衝有資料就會一直觸發事件,直到緩衝區沒有資料。

1. 對於讀操作

只要緩衝內容不為空,lt模式返回讀就緒。

2. 對於寫操作

只要緩衝區還不滿,lt模式會返回寫就緒。

邊緣觸發:

1. 對於讀操作

(1)當緩衝區由不可讀變為可讀的時候,即緩衝區由空變為不空的時候。

(2)當有新資料到達時,即緩衝區中的待讀資料變多的時候。

(3)當緩衝區有資料可讀,且應用程序對相應的描述符進行epoll_ctl_mod 修改epollin事件時。

2. 對於寫操作

(1)當緩衝區由不可寫變為可寫時。

(2)當有舊資料被傳送走,即緩衝區中的內容變少的時候。

(3)當緩衝區有空間可寫,且應用程序對相應的描述符進行epoll_ctl_mod 修改epollout事件時。

#include #include #include int main()}}

}

我們輸入了一些資料到  stdin_fileno(標準輸入)中,但是沒有讀取資料。所以會一直觸發事件,就會一直列印hello world。

執行結果:

$ ./a.out

aaa //自己輸入的資料

hello world

hello world

hello world

hello world

hello world

^c

#include #include #include int main()}}

}

只有緩衝區發生變化才會觸發。

執行結果:

$ ./a.out 

123 //自己輸入的資料

hello world

123hello world

123hello world

邊緣觸發方式下,以阻塞方式工作的read & write函式有可能引起伺服器端的長時間停頓。因此,邊緣觸發方式中一定要採用非阻塞read&

write函式。

#include #include #include #include int main()}}

}

執行結果:和條件觸發一樣

$ ./a.out

aaa //自己輸入的資料

hello world

hello world

hello world

hello world

hello world

^c

非阻塞邊緣觸發伺服器**:

執行結果:

$ ./ser 9190

return epoll_wait

connected client: 5

return epoll_wait

return epoll_wait

return epoll_wait

return epoll_wait

return epoll_wait

closed client: 5

$ ./cli 192.168.1.141 9190

input message(q to quit) : asdfasdf

message from server: asdfasdf

input message(q to quit) : asdfasf

message from server: asdfasf

input message(q to quit) : sdfasdf

message from server: sdfasdf

input message(q to quit) : asdfasd

message from server: asdfasd

input message(q to quit) : ^c

伺服器:

#include #include #include #include #include #include #include #include #include #define buf_size 4

#define epoll_size 50

void setnonblockingmode(int fd);

void error_handling(char *buf);

int main(int argc, char *ar**)

serv_sock=socket(pf_inet, sock_stream, 0);

memset(&serv_adr, 0, sizeof(serv_adr));

serv_adr.sin_family=af_inet;

serv_adr.sin_addr.s_addr=htonl(inaddr_any);

serv_adr.sin_port=htons(atoi(ar**[1]));

if(bind(serv_sock, (struct sockaddr*) &serv_adr, sizeof(serv_adr))==-1)

error_handling("bind() error");

if(listen(serv_sock, 5)==-1)

error_handling("listen() error");

epfd=epoll_create(epoll_size);

ep_events=(struct epoll_event*)malloc(sizeof(struct epoll_event)*epoll_size);

setnonblockingmode(serv_sock);

event.events=epollin;

event.data.fd=serv_sock;

epoll_ctl(epfd, epoll_ctl_add, serv_sock, &event);

while(1)

puts("return epoll_wait");

for(i=0; i客服端:

#include #include #include #include #include #include #define buf_size 1024

void error_handling(char *message);

int main(int argc, char* ar**)

sock = socket(pf_inet, sock_stream, 0);

if(sock == -1)

error_handling("socket() error");

memset(&serv_addr, 0, sizeof(serv_addr));

serv_addr.sin_family=af_inet;

serv_addr.sin_addr.s_addr=inet_addr(ar**[1]);

serv_addr.sin_port=htons(atoi(ar**[2]));

if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)

error_handling("connect() error i");

while(1)

close(sock);

return 0;

}void error_handling(char *message)

epoll的水平觸發和邊緣觸發

即level triggered and edge triggered 簡單說來 level triggered 只要事件是處於就緒狀態,你每詢問一次,就告訴你一次它處於就緒狀態。edge triggered 只有在狀態改變的時候告訴你,這也是為什麼et模式下,建議用非阻塞的socket。下面我們來...

epoll的水平觸發和邊緣觸發

水平觸發 level triggered 當滿足條件時,觸發.select和poll採用該方式 邊緣觸發 edge triggered 當狀態變化時,觸發.訊號驅動 signal driven i o 採用該方式 過程 當資料到來的時候,觸發器滿足條件,傳送通知,程序接收到通知後,請求核心讀取資料....

邊緣觸發和水平(條件)觸發

條件觸發 lt 和邊緣觸發 et 的區別在於事件的時間點 邊緣觸發 每當狀態變化時發生乙個io事件 條件觸發 只要滿足條件就發生乙個io事件 在條件觸發方式中,只要輸入緩衝有資料就會一直通知該事件。例如 伺服器輸入緩衝收到50位元組的資料時,伺服器端作業系統將通知該事件 註冊到發生變化的檔案描述符 ...