epoll是一個特別重要的概念,常常用於處理服務端的並發問題。當服務端的在線人數越來越多,會導致系統資源吃緊,I/O效率越來越慢,這時候就應該考慮epoll了。epoll是Linux內核為處理大批句柄而作改進的poll,是Linux特有的I/O函數。其特點如下:
1.epoll是Linux下多路復用IO接口select/poll的增強版本。其實現和使用方式與select/poll有很多不同,epoll通過一組函數來完成有關任務,而不是一個函數。
2.epoll之所以高效,是因為epoll將用戶關心的文件描述符放到內核里的一個事件表中,而不是像select/poll每次調用都需要重復傳入文件描述符集或事件集。比如當一個事件發生(比如說讀事件),epoll無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入就緒隊列的描述符集合就行了。
3.epoll有兩種工作方式,LT(level triggered):水平觸發和ET(edge-triggered):邊沿觸發。LT是select/poll使用的觸發方式,比較低效;而ET是epoll的高速工作方式。
通俗理解就是,比如說有一堆女孩,有的很漂亮,有的很鳳姐。現在你想找漂亮的女孩聊天,LT就是你需要把這一堆女孩全都看一遍,才可以找到其中的漂亮的(就緒事件);而ET是你的小弟(內核)將N個漂亮的女孩編號告訴你,你直接去看就好,所以epoll很高效。另外,還記得我的上一篇文章中小明找女神聊天的例子嗎?采用非阻塞方式,小明還需要每隔十分鍾回來看一下(select);如果小明有小弟(內核)幫他守在大門口,女神回來了,小弟會主動打電話,告訴小明女神回來了,快來處理吧!這就是epoll。
epoll共有三個函數,如下:
- 1、int epoll_create(int size)
- // 創建一個epoll句柄,參數size用來告訴內核監聽的數目,size為epoll所支持的最大句柄數
- 2、int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
- /*函數功能: epoll事件注冊函數
- 參數epfd為epoll的句柄,即epoll_create返回值
- 參數op表示動作,用3個宏來表示:
- EPOLL_CTL_ADD(注冊新的fd到epfd),
- EPOLL_CTL_MOD(修改已經注冊的fd的監聽事件),
- EPOLL_CTL_DEL(從epfd刪除一個fd);
- 其中參數fd為需要監聽的標示符;
- 參數event告訴內核需要監聽的事件,event的結構如下:*/
- struct epoll_event {
- __uint32_t events; //Epoll events
- epoll_data_t data; //User data variable
- };
- 3、 int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
- //等待事件的產生,函數返回需要處理的事件數目(該數目是就緒事件的數目,就是前面所說漂亮女孩的個數N)
因此,服務端epoll的時候,步驟如下:
1.調用epoll_create函數在Linux內核中創建一個事件表;
2.然后將文件描述符(監聽套接字)添加到所創建的事件表中;
3.在主循環中,調用epoll_wait等待返回就緒的文件描述符集合;
4.分別處理就緒的事件集合
下面介紹下如何將一個socket添加到內核事件表中,如下:
- //將文件描述符fd添加到epollfd標示的內核事件表中, 並注冊EPOLLIN和EPOOLET事件,EPOLLIN是數據可讀事件;EPOOLET表明是ET工作方式。最后將文件描述符設置非阻塞方式
- /**
- * @param epollfd: epoll句柄
- * @param fd: 文件描述符
- * @param enable_et : enable_et = true,
- 采用epoll的ET工作方式;否則采用LT工作方式
- **/
- void addfd( int epollfd, int fd, bool enable_et )
- {
- struct epoll_event ev;
- ev.data.fd = fd;
- ev.events = EPOLLIN;
- if( enable_et )
- ev.events = EPOLLIN | EPOLLET;
- epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
- setnonblocking(fd);
- printf("fd added to epoll!\n\n");
- }
