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

2021-08-21 03:10:07 字數 3709 閱讀 7414

條件觸發(lt)和邊緣觸發(et)的區別在於事件的時間點

邊緣觸發:每當狀態變化時發生乙個io事件

條件觸發:只要滿足條件就發生乙個io事件

在條件觸發方式中,只要輸入緩衝有資料就會一直通知該事件。

例如:伺服器輸入緩衝收到50位元組的資料時,伺服器端作業系統將通知該事件(註冊到發生變化的檔案描述符)。但伺服器端讀取20位元組後還剩30位元組的情況下,仍會註冊事件。也就是說,條件觸發方式中,只要輸入緩衝中還剩有資料,就將以事件方式再次註冊。

而邊緣觸發中輸入緩衝收到資料時僅註冊1次該事件。即使輸入緩衝中還留有資料,也不會再進行註冊。

下面是條件觸發的示例**:

#include#include#include#include#include#include#include#define epoll_size 50

#define buf_size 4

void error_handling(char *buf);

int main(int argc,char **argv)

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(argv[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=malloc(sizeof(struct epoll_event)*epoll_size);

event.events=epollin;

event.data.fd=serv_sock;

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

while(1)

puts("epoll_wait() error");

for(i=0;i邊緣觸發的伺服器端實現中必知的兩點

1. 通過errno變數驗證錯誤原因

2. 為了完成非阻塞i/o,更改套接字特性

linux的套接字相關函式一般通過返回-1通知發生了錯誤。雖然知道發生了錯誤,但僅憑這些內容無法得知產生錯誤的原因。因此,為了在發生錯誤時提供額外的資訊,linux宣告了如下全域性變數:

int errno;

為了訪問該變數,需要引入error.h標頭檔案,因為此標頭檔案中有上述變數的extern宣告。另外,每種函式發生錯誤時,儲存到errno變數中的值都不同,沒必要記住所有可能的值。

read函式發現輸入緩衝中沒有資料可讀時返回-1,同時在errno中儲存eagain常量。

下面是將套接字改為非阻塞方式的方法。linux提供更改或讀取檔案屬性的如下方法:

#includeint fcntl(int filedes,int cmd,...);

//成功時返回cmd引數相關值,失敗時返回-1

//filedes---屬性更改目標的檔案描述符

//cmd---表示函式呼叫的目的

fcntl具有可變引數的形式。如果向第二個引數傳遞f_getfl,可以獲得第乙個引數所指的檔案描述符屬性。反之,如果傳遞f_setfl,可以更改檔案描述符屬性。若希望將檔案(套接字)改為非阻塞模式,需要以下兩種語句:

int flag=fcntl(fd,f_getfl,0);

fcntl(fd,f_setfl,flag | o_nonblock);

通過第一條語句獲取之前設定的屬性資訊,通過第二條語句在此基礎上新增非阻塞o_nonblock標誌。呼叫read&write函式時,無論是否存在資料,都會形成非阻塞檔案。

實現邊緣觸發的回聲伺服器端

首先說明為何需要通過errno確認錯誤的原因:

邊緣觸發方式中,接收資料時僅註冊1次該事件

就因為這種特點,一旦發生輸入相關事件,就應該讀取輸入緩衝中的全部資料。因此需要驗證輸入緩衝是否為空。

read函式返回-1,變數errno中的值為eagain時,說明沒有資料可讀。

既然如此,為何需要將套接字變成非阻塞模式?邊緣觸發方式下,以阻塞模式工作的read & write函式有可能引起伺服器端的長時間停頓。因此,邊緣觸發方式一定要採用非阻塞read & write函式。

下面是以邊緣觸發方式工作的回聲伺服器端示例:

#include#include#include#include#include#include#include#include#include#define epoll_size 50

#define buf_size 4

void error_handling(char *buf);

void setnonblockingmode(int fd);

int main(int argc,char **argv)

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(argv[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=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;ielse

else if(str_len<0)

else}}

} }

close(serv_sock);

close(epfd);

return 0;

}void setnonblockingmode(int fd)

void error_handling(char *buf)

epoll 水平觸發 邊緣觸發

水平觸發 只要緩衝區還有資料,核心就還會通知使用者。使用者如果第一次讀取資料沒讀完,即使沒有任何新的操作觸發,還是可以繼續通過epoll wait來獲取事件 邊緣觸發 只有當新事件觸發的時候,才能通過epoll wait來獲取資料,如果第一次讀取資料沒讀完,就只能等待下一次事件觸發來獲取餘下的資料。...

epoll 水平觸發 邊緣觸發

先簡單比較一下level trigger 和 edge trigger 模式的不同。讓我們換乙個角度來理解et模式,事實上,epoll的et模式其實就是socket io完全狀態機。當socket由不可讀變成可讀時,epoll的et模式返回read 事件。對於read 事件,開發者需要保證把讀取緩衝...

水平觸發與邊緣觸發

今天開始封裝c的socket的基礎,在封裝的時候意識到這樣乙個問題,如果我現在fd的接收緩衝區中有2048位元組的資料,但是我唯讀出來1024個位元組的資料,當我下次select的時候 這之間沒有網路資料過來 還會檢測到該select可讀嗎?這樣就引申出來水linux的io多路復用中的水平觸發模式和...