文章目錄
- 概述
- 1. epoll_create - 創建一個epoll實例
- 2. epoll_ctl - 控制epoll實例的事件
- 結構體介紹
- events取值:
- data: 聯合體(共用體):
- 3. epoll_wait - 等待事件發生
- 偽代碼
- 總結
概述
在網絡編程中,高效地處理大量并發連接是一個關鍵問題。而Linux提供的epoll機制成為了解決這個問題的重要工具。epoll是一種I/O事件通知機制,通過三個主要函數,即epoll_create、epoll_ctl和epoll_wait,實現了高性能的事件驅動并發編程。讓我們深入了解這三個函數以及它們的使用方法。
1. epoll_create - 創建一個epoll實例
int epoll_create(int size);
size:創建的紅黑樹的監聽節點數量。(僅供內核參考。)
返回值:指向新創建的紅黑樹的根節點的 fd。
-1:代表錯誤
2. epoll_ctl - 控制epoll實例的事件
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epfd:epoll_create 函數的返回值。 epfd
op:對該監聽紅黑數所做的操作。
EPOLL_CTL_ADD 添加fd到 監聽紅黑樹
EPOLL_CTL_MOD 修改fd在 監聽紅黑樹上的監聽事件。
EPOLL_CTL_DEL 將一個fd 從監聽紅黑樹上摘下(取消監聽)
fd:待監聽的fd
event: 本質 struct epoll_event 結構體指針
返回值:成功 0; 失敗: -1 errno
結構體介紹
struct epoll_event {__uint32_t events; /* Epoll events */epoll_data_t data; /* User data variable */};typedef union epoll_data {void *ptr;int fd;uint32_t u32;uint64_t u64;} epoll_data_t;
events取值:
EPOLLIN : 表示對應的文件描述符可以讀(包括對端SOCKET正常關閉)
EPOLLOUT: 表示對應的文件描述符可以寫
EPOLLERR: 表示對應的文件描述符發生錯誤
等等(不重要)
data: 聯合體(共用體):
int fd; 對應監聽事件的 fd
void *ptr; 回調函數
uint32_t u32;
uint64_t u64;
3. epoll_wait - 等待事件發生
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
epoll_wait函數用于等待事件發生,當事件發生時將返回就緒的文件描述符以及對應的事件類型。參數包括:
epfd:epoll_create 函數的返回值。 epfd
events:傳出參數,【數組】, 滿足監聽條件的 那些 fd 結構體。
maxevents:上面數組元素的總個數。 eg:struct epoll_event evnets[1024]->1024
timeout:
-1: 阻塞
0: 不阻塞
大于0: 超時時間 (毫秒)
返回值:
大于0: 滿足監聽的 總個數。 可以用作循環上限。
0: 沒有fd滿足監聽事件
-1:失敗。 errno
偽代碼
關于代碼實現可以參考:鏈接
epoll實現多路IO轉接思路:
lfd = socket(); 監聽連接事件lfd
bind();
listen();int epfd = epoll_create(1024); epfd, 監聽紅黑樹的樹根。struct epoll_event tep, ep[1024]; tep, 用來設置單個fd屬性, ep 是 epoll_wait() 傳出的滿足監聽事件的數組。tep.events = EPOLLIN; 初始化 lfd的監聽屬性。
tep.data.fd = lfdepoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &tep); 將 lfd 添加到監聽紅黑樹上。while (1) {ret = epoll_wait(epfd, ep,1024, -1); 實施監聽for (i = 0; i < ret; i++) {if (ep[i].data.fd == lfd) { // lfd 滿足讀事件,有新的客戶端發起連接請求cfd = Accept();tep.events = EPOLLIN; 初始化 cfd的監聽屬性。tep.data.fd = cfd;epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &tep);} else { cfd 們 滿足讀事件, 有客戶端寫數據來。n = read(ep[i].data.fd, buf, sizeof(buf));if ( n == 0) {close(ep[i].data.fd);epoll_ctl(epfd, EPOLL_CTL_DEL, ep[i].data.fd , NULL); // 將關閉的cfd,從監聽樹上摘下。} else if (n > 0) {小--大write(ep[i].data.fd, buf, n);}}}
總結
通過使用epoll_create、epoll_ctl和epoll_wait這三個主要函數,我們可以充分利用Linux的epoll機制來實現高效的事件驅動并發編程。首先,通過創建epoll實例,我們能夠監控多個文件描述符。然后,使用epoll_ctl函數來添加、修改和刪除需要監控的事件。最后,通過調用epoll_wait函數來等待事件的發生并處理就緒的文件描述符。
這些函數的合理使用可以幫助我們有效地管理大量并發連接,提高系統的性能和響應能力。當然,在實際應用中,我們還需要結合其他的網絡編程知識和技巧,以實現更加穩定和高效的網絡應用程序