epoll 使用詳解

2021-09-08 08:17:39 字數 4768 閱讀 3370

epoll是linux核心中的一種可擴充套件io事件處理機制,最早在 linux 2.5.44核心中引入,可被用於代替posix select 和 poll 系統呼叫,並且在具有大量應用程式請求時能夠獲得較好的效能( 此時被監視的檔案描述符數目非常大,與舊的 select 和 poll 系統呼叫完成操作所需 o(n) 不同, epoll能在o(1)時間內完成操作,所以效能相當高),epoll 與 freebsd的kqueue類似,都向使用者空間提供了自己的檔案描述符來進行操作。

int epoll_create(int size);

建立乙個epoll的控制代碼,size用來告訴核心需要監聽的數目一共有多大。當建立好epoll控制代碼後,它就是會占用乙個fd值,在linux下如果檢視/proc/程序id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須呼叫close() 關閉,否則可能導致fd被耗盡。

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

epoll的事件註冊函式,第乙個引數是 epoll_create() 的返回值,第二個引數表示動作,使用如下三個巨集來表示:

epoll_ctl_add    //

註冊新的fd到epfd中;

epoll_ctl_mod //

修改已經註冊的fd的監聽事件;

epoll_ctl_del //

從epfd中刪除乙個fd;

第三個引數是需要監聽的fd,第四個引數是告訴核心需要監聽什麼事,struct epoll_event 結構如下:

typedef union epoll_data

epoll_data_t;

struct epoll_event ;

events 可以是以下幾個巨集的集合:

epollin //

表示對應的檔案描述符可以讀(包括對端socket正常關閉);

epollout//

表示對應的檔案描述符可以寫;

epollpri//

表示對應的檔案描述符有緊急的資料可讀(這裡應該表示有帶外資料到來);

epollerr//

表示對應的檔案描述符發生錯誤;

epollhup    //

表示對應的檔案描述符被結束通話;

epollet//

將epoll設為邊緣觸發(edge triggered)模式,這是相對於水平觸發(level triggered)來說的。

epolloneshot//

只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到epoll佇列裡。

當對方關閉連線(fin), epollerr,都可以認為是一種epollin事件,在read的時候分別有0,-1兩個返回值。

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

引數events用來從核心得到事件的集合,maxevents 告之核心這個events有多大,這個 maxevents 的值不能大於建立 epoll_create() 時的size,引數 timeout 是超時時間(毫秒,0會立即返回,-1將不確定,也有說法說是永久阻塞)。該函式返回需要處理的事件數目,如返回0表示已超時。

epoll事件有兩種模型level triggered (lt)edge triggered (et):

lt(level triggered,水平觸發模式)是預設的工作方式,並且同時支援 block 和 non-block socket。在這種做法中,核心告訴你乙個檔案描述符是否就緒了,然後你可以對這個就緒的fd進行io操作。如果你不作任何操作,核心還是會繼續通知你的,所以,這種模式程式設計出錯誤可能性要小一點。

et(edge-triggered,邊緣觸發模式)是高速工作方式,只支援no-block socket。在這種模式下,當描述符從未就緒變為就緒時,核心通過epoll告訴你。然後它會假設你知道檔案描述符已經就緒,並且不會再為那個檔案描述符傳送更多的就緒通知,等到下次有新的資料進來的時候才會再次出發就緒事件。

我們將實現乙個簡單的tcp 伺服器,該迷你伺服器將會在標準輸出上列印處客戶端傳送的資料,首先我們建立並繫結乙個 tcp 套接字:

static

intcreate_and_bind (char *port)

for (rp = result; rp != null; rp = rp->ai_next)

close (sfd);

}if (rp == null)

freeaddrinfo (result);

return sfd;

}

create_and_bind() 包含了如何建立 ipv4 和 ipv6 套接字的**塊,它接受一字串作為埠引數,並在 result 中返回乙個 addrinfo 結構,

struct addrinfo

;

如果函式成功則返回套接字,如果失敗,則返回 -1,

下面,我們將乙個套接字設定為非阻塞形式,函式如下:

static

intmake_socket_non_blocking (int sfd)

flags |= o_nonblock;

s = fcntl (sfd, f_setfl, flags);

if (s == -1)

return

0;}

接下來,便是主函式**,主要用於事件迴圈:

#define maxevents 64

intmain (int argc, char *ar**)

sfd = create_and_bind (ar**[1]);

if (sfd == -1)

abort ();

s = make_socket_non_blocking (sfd);

if (s == -1)

abort ();

s = listen (sfd, somaxconn);

if (s == -1)

efd = epoll_create1 (0);

if (efd == -1)

event.data.fd = sfd;

event.events = epollin | epollet;

s = epoll_ctl (efd, epoll_ctl_add, sfd, &event);

if (s == -1)

/*buffer where events are returned

*/events = calloc (maxevents, sizeof

event);

/*the event loop

*/while (1)

else

if (sfd == events[i].data.fd)

else

}s = getnameinfo (&in_addr, in_len,

hbuf, sizeof hbuf,

sbuf, sizeof sbuf,

ni_numerichost | ni_numericserv);

if (s == 0)

/*make the incoming socket non-blocking and add it to the

list of fds to monitor.

*/s = make_socket_non_blocking (infd);

if (s == -1)

abort ();

event.data.fd = infd;

event.events = epollin | epollet;

s = epoll_ctl (efd, epoll_ctl_add, infd, &event);

if (s == -1)

}continue;

}else

break;

}else

if (count == 0)

/*write the buffer to standard output

*/s = write (1, buf, count);

if (s == -1)

}if (done)}}

}free (events);

close (sfd);

return exit_success;

}

main() 首先呼叫create_and_bind() 建立套接字,然後將其設定為非阻塞的,再呼叫listen(2)。之後建立乙個epoll 例項 efd(檔案描述符),並將其加入到sfd的監聽套接字中以邊沿觸發方式等待事件輸入。

外層的 while 迴圈是主事件迴圈,它呼叫了epoll_wait(2),此時執行緒仍然被阻塞等待事件,當事件可用時,epoll_wait(2) 將會在events引數中返回可用事件。

epoll 例項 efd 在每次事件到來並需要新增新的監聽時就會得到更新,並刪除死亡的鏈結。

當事件可用時,可能有一下三種型別:

(全文完)

epoll使用詳解(精髓)

epoll i o event notification facility 在linux的網路程式設計中,很長的時間都在使用select來做事件觸發。在linux新的核心中,有了一種替換它的機制,就是epoll。相比於select,epoll最大的好處在於它不會隨著監聽fd數目的增長而降低效率。因為...

epoll使用詳解(精髓)

epoll i o event notification facility 在linux的網路程式設計中,很長的時間都在使用select來做事件觸發。在linux新的核心中,有了一種替換它的機制,就是epoll。相比於select,epoll最大的好處在於它不會隨著監聽fd數目的增長而降低效率。因為...

epoll使用詳解(精髓)

epoll i o event notification facility 在linux的網路程式設計中,很長的時間都在使用select來做事件觸發。在linux新的核心中,有了一種替換它的機制,就是epoll。相比於select,epoll最大的好處在於它不會隨著監聽fd數目的增長而降低效率。因為...