十二 優於select的epoll

2021-08-20 09:16:21 字數 3937 閱讀 3730

基於select

的i/o

復用技術速度慢的原因:

呼叫select

函式後常見的針對所有檔案描述符的迴圈語句。

每次呼叫select

函式後都需要向該函式傳遞監視物件資訊。

epoll

函式的優點正好與select

缺點相反:

無需編寫以監視狀態變化為目的的針對所有檔案描述符的迴圈語句。

呼叫對應於select

函式的epoll-wait

函式時無需每次傳遞監視物件資訊。

實現epoll

時必要的函式:

epoll_create:

建立儲存epoll

檔案描述符的空間。

epoll_ctl

:向空間註冊或銷毀檔案描述符。

epoll_wait

:與select

函式類似,等待檔案描述符發生變化。

宣告足夠大的epoll_event

結構體陣列後,傳遞給epoll_wait

函式時,發生變化的檔案描述符資訊將被填入該陣列。

因此,無需像select

函式那樣針對所有檔案描述符進行迴圈。

基於epoll

的回聲伺服器端:

#include #include #include #include #include #include #include #define buf_size 100

#define epoll_size 50

void error_handling(char *buf);

int main(int argc, const char * argv)

serv_sock = socket(pf_inet, sock_stream, 0);

if(serv_sock == -1)

error_handling("socket() error");

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");

//建立檔案描述符的儲存空間稱為「epoll例程」

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)

//服務端套接字和客服端套接字

for (i = 0; i < event_cnt; i++)

else //連線之後傳遞資料

else}}

}close(serv_sock);

close(epfd);

return 0;

}void error_handling(char *message)

條件觸發和邊緣觸發

條件觸法方式中,

只要輸入緩衝中還剩有資料,

就將以事件方式再次註冊.epoll

預設使用該方式.

邊緣觸發中輸入緩衝收到資料時僅註冊一次事件,

即使輸入緩衝中還留有資料,

也不會再進行註冊.

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

1.邊緣觸發方式中,

接收資料時僅註冊一次該事件,

因此,一旦發生輸入相關事件,

就應該讀取輸入緩衝中的全部資料.

因此需要驗證輸入緩衝是否為空.

read

函式返回-1,

變數error

中的值為eagain

時,說明沒有資料可讀.

2..邊緣觸發方式下,

以阻塞方式工作的read

和write

函式有可能引起伺服器端的長時間停頓,

所以需要將套接字變成非阻塞模式.

#include#include#include#include#include#include#include#include#include#define buf_size 4          //驗證邊緣觸發的工作方式,將緩衝設定為4位元組  

#define epoll_size 50

void error_handling(char *message);

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); //建立epoll例程檔案描述符

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); //在epfd內註冊監視serv__sock,監視其讀取資料的情況

while(1)

puts("return epoll_wait");

for (i = 0; i < event_cnt; i++)

else //連線客戶端套接字讀取資料

else if(str_len < 0)

else

} }

} }

close(serv_sock);

close(epfd);

return 0;

} void setnonblockingmode(int fd)

void error_handling(char *message)

從實現模型的角度看,

邊緣觸發更有可能帶來高效能,

但不能簡單地認為」只要使用邊緣觸發就一定能提高速度」.

unique ptr優於auto ptr的原因

使用auto ptr不當的後果 int main aptr1將控制權移交給aptr2,然而編譯階段並不認為輸出 aptr1是錯誤的,然而編譯階段錯誤總比執行階段錯誤要好 int main unique ptr的指標不允許上述賦值,因為uptr1之後的操作可能會導致執行階段失敗 unique ptr只...

C 的函式物件優於函式指標地方

自 在c 程式語言中,有很多功能都與c語言相通,比如指標的應用等等。在這裡我們介紹的則是一種類似於函式指標的c 函式物件的相關介紹。c 函式物件不是函式指標。但是,在程式 中,它的呼叫方式與函式指標一樣,後面加個括號就可以了。這是入門級的隨筆,說的是函式物件的定義,使用,以及與函式指標,成員函式指標...

select的列子說明select內部實現原理

1 select內部是個陣列,而epoll內部結構是紅黑二叉樹 2 select查詢起來慢,而epoll查詢起來快 3 每次迴圈,內部都要發生拷貝 檢視相關 而epoll不需要這樣的操作,也就是初始化一次拷貝 include include include include include int m...