Epoll為我們帶來什么 | |
Q:網(wǎng)絡服務器的瓶頸在哪? A:IO效率。 在大家苦苦的為在線人數(shù)的增長而導致的系統(tǒng)資源吃緊上的問題正在發(fā)愁的時候,Linux 2.6內(nèi)核中提供的System Epoll為我們提供了一套完美的解決方案。傳統(tǒng)的select以及poll的效率會因為在線人數(shù)的線形遞增而導致呈二次乃至三次方的下降,這些直接導致了網(wǎng)絡服務器可以支持的人數(shù)有了個比較明顯的限制。 自從Linux提供了/dev/epoll的設備以及后來2.6內(nèi)核中對/dev/epoll設備的訪問的封裝(System Epoll)之后,這種現(xiàn)象得到了大大的緩解,如果說幾個月前,大家還對epoll不熟悉,那么現(xiàn)在來說的話,epoll的應用已經(jīng)得到了大范圍的普及。 那么究竟如何來使用epoll呢?其實非常簡單。 通過在包含一個頭文件#include <sys/epoll.h>以及幾個簡單的API將可以大大的提高你的網(wǎng)絡服務器的支持人數(shù)。 首先通過create_epoll(int maxfds)來創(chuàng)建一個epoll的句柄,其中maxfds為你epoll所支持的最大句柄數(shù)。這個函數(shù)會返回一個新的epoll句柄,之后的所有操作將通過這個句柄來進行操作。在用完之后,記得用close()來關閉這個創(chuàng)建出來的epoll句柄。 之后在你的網(wǎng)絡主循環(huán)里面,每一幀的調(diào)用epoll_wait(int epfd, epoll_event events, int max events, int timeout)來查詢所有的網(wǎng)絡接口,看哪一個可以讀,哪一個可以寫了?;镜恼Z法為: nfds = epoll_wait(kdpfd, events, maxevents, -1); 其中kdpfd為用epoll_create創(chuàng)建之后的句柄,events是一個epoll_event*的指針,當epoll_wait這個函數(shù)操作成功之后,epoll_events里面將儲存所有的讀寫事件。max_events是當前需要監(jiān)聽的所有socket句柄數(shù)。最后一個timeout是epoll_wait的超時,為0的時候表示馬上返回,為-1的時候表示一直等下去,直到有事件范圍,為任意正整數(shù)的時候表示等這么長的時間,如果一直沒有事件,則范圍。一般如果網(wǎng)絡主循環(huán)是單獨的線程的話,可以用-1來等,這樣可以保證一些效率,如果是和主邏輯在同一個線程的話,則可以用0來保證主循環(huán)的效率。 epoll_wait范圍之后應該是一個循環(huán),遍利所有的事件: for(n = 0; n < nfds; ++n) { if(events[n].data.fd == listener) { //如果是主socket的事件的話,則表示有新連接進入了,進行新連接的處理。 client = accept(listener, (struct sockaddr *) &local, &addrlen); if(client < 0){ perror("accept"); continue; } setnonblocking(client); // 將新連接置于非阻塞模式 ev.events = EPOLLIN | EPOLLET; // 并且將新連接也加入EPOLL的監(jiān)聽隊列。 注意,這里的參數(shù)EPOLLIN | EPOLLET并沒有設置對寫socket的監(jiān)聽,如果有寫操作的話,這個時候epoll是不會返回事件的,如果要對寫操作也監(jiān)聽的話,應該是EPOLLIN | EPOLLOUT | EPOLLET ev.data.fd = client; if (epoll_ctl(kdpfd, EPOLL_CTL_ADD, client, &ev) < 0) { // 設置好event之后,將這個新的event通過epoll_ctl加入到epoll的監(jiān)聽隊列里面,這里用EPOLL_CTL_ADD來加一個新的epoll事件,通過EPOLL_CTL_DEL來減少一個epoll事件,通過EPOLL_CTL_MOD來改變一個事件的監(jiān)聽方式。 fprintf(stderr, "epoll set insertion error: fd=%d0, client); return -1; } } else // 如果不是主socket的事件的話,則代表是一個用戶socket的事件,則來處理這個用戶socket的事情,比如說read(fd,xxx)之類的,或者一些其他的處理。 do_use_fd(events[n].data.fd); } 對,epoll的操作就這么簡單,總共不過4個API:epoll_create, epoll_ctl, epoll_wait和close。 如果您對epoll的效率還不太了解,請參考我之前關于網(wǎng)絡游戲的網(wǎng)絡編程等相關的文章。 世界變了,原來擔心的問題,現(xiàn)在已經(jīng)不是問題了。 |