1、selectlinux
1.select簡介
數組
系統提供select函數來實現多路複用輸入/輸出模型。select系統調用是用來讓咱們的程序監視多個文件句柄的狀態變化的。程序會停在select這裏等待,直到被監視的文件句柄有一個或多個發生了狀態改變。socket
文件句柄,其實就是一個整數,咱們最熟悉的句柄是0、一、2三 個,0是標準輸入,1是標準輸出,2是標準錯誤輸出。0、一、2是整數表示的,對應的FILE * 結構的表示就是stdin、stdout、stderr。ide
2.select函數函數
(1)參數nfds是須要監視的最大的文件描述符值+1; 性能
(2)rdset,wrset,exset分別對應於須要檢測的可讀文件描述符的集合,可寫文件描述符的集合及異常文件描述符的集合。 測試
(3)參數timeout爲結構timeval,用來設置select()的等待時間。spa
struct timeval結構用於描述一段時間長度,若是在這個時間內,須要監視的描述符沒有事件發生則函數返回,返回值爲0。指針
(4)FD_CLR(inr fd,fd_set* set);用來清除描述詞組set中相關fd 的位。 blog
FD_ISSET(int fd,fd_set *set);用來測試描述詞組set中相關fd 的位是否爲真。
FD_SET(int fd,fd_set*set);用來設置描述詞組set中相關fd的位。
FD_ZERO(fd_set *set);用來清除描述詞組set的所有位。
2、poll
不一樣與select使用三個位圖來表示三個fdset的方式,poll使用一個 pollfd的指針實現。
pollfd結構包含了要監視的event和發生的event,再也不使用select「參數-值」傳遞的方式。同時, pollfd並無最大數量限制(可是數量過大後性能也是會降低)。和select函數同樣,poll返回後,須要輪詢pollfd來獲取就緒的描述符。
3、epoll
epoll是爲處理大批量句柄而做了改進的poll。固然,這不是 2.6內核纔有的,它是在2.5.44內核中被引進的(epoll(4) is a new API introduced in Linux kernel 2.5.44),它幾乎具有了以前所說的一切優勢,被公認爲Linux2.6下性能最好的多路I/O就緒通知方法。
epoll只有epoll_create,epoll_ctl,epoll_wait 3個系統調用。
1.int epoll_create(int size);
建立一個epoll的句柄。自從linux2.6.8以後,size參數是被忽略的。須要注意的是,當建立好epoll句柄後,它就是會佔用一個fd值,在linux下若是查看/proc/進程id/fd/,是可以看到這個fd的,因此在使用完epoll後,必須調用close()關閉,不然可能致使fd被耗盡。
2.int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epoll的事件註冊函數,它不一樣於select()是在監聽事件時告訴內核要監聽什麼類型的事件,而是在這裏先註冊要監聽的事件類型。
(1)第一個參數是epoll_create()的返回值。
(2)第二個參數表示動做,用三個宏來表示:
EPOLL_CTL_ADD:註冊新的fd到epfd中;
EPOLL_CTL_MOD:修改已經註冊的fd的監聽事;
EPOLL_CTL_DEL:從epfd中刪除一個fd;
(3)第三個參數是須要監聽的fd。
(4) 第四個參數是告訴內核須要監聽什麼事,struct epoll_event結構以下:
EPOLLIN :表示對應的文件描述符能夠讀(包括對端SOCKET正常關閉);
EPOLLOUT:表示對應的文件描述符能夠寫;
EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裏應該表示有帶外數據到來);
EPOLLERR:表示對應的文件描述符發生錯誤;
EPOLLHUP:表示對應的文件描述符被掛斷;
EPOLLET: 將EPOLL設爲邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來講的;
在將RFD添加到epoll描述符的時候使用了EPOLLET標誌,那麼在調用 epoll_wait以後將有可能會掛起,由於剩餘的數據還存在於文件的輸入緩衝區內,並且數據發出端還在等待一個針對已經發出數據的反饋信息。只有在監視的文件句柄上發生了某個事件的時候 ET工做模式纔會彙報事件。所以在調用epoll_wait以後,調用者可能會放棄等待仍在存在於文件輸入緩衝區內的剩餘數據。epoll工做在ET模式的時候,必須使用非阻塞套接口,以免因爲一個文件 句柄的阻塞讀/阻塞寫操做把處理多個文件描述符的任務餓死。
以LT方式調用epoll接口的時候,它就至關於一個速度比較快的poll,而且不管後面的數據是否被使用,所以他們具備一樣的職能。由於即便使用ET模式的epoll,在收到多 個chunk的數據的時候仍然會產生多個事件。調用者能夠設定EPOLLONESHOT標誌,在 epoll_wait收到事件後epoll會與事件關聯的文件句柄從epoll描述符中禁止掉。所以當 EPOLLONESHOT設定後,使用帶有 EPOLL_CTL_MOD標誌的epoll_ctl處理文件句柄就 成爲調用者必須做的事情。
EPOLLONESHOT:只監聽一次事件,當監聽完此次事件以後,若是還須要繼續監聽這個 socket的話,須要再次把這個socket加入到EPOLL隊列裏。
3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
收集在epoll監控的事件中已經發送的事件。參數events是分配好的epoll_event結構體數組,epoll將會把發生的事件賦值到events數組中(events不能夠是空指針,內核只負責把數據復 制到這個events數組中,不會去幫助咱們在用戶態中分配內存)。maxevents告以內核這個 events有多大,這個 maxevents的值不能大於建立epoll_create()時的size,參數timeout是超時 時間(毫秒,0會當即返回,-1將不肯定,也有說法說是永久阻塞)。若是函數調用成功,返回對應I/O上已準備好的文件描述符數目,如返回0表示已超時。
4、select、poll、epoll的比較
每次調用select,都須要把fd集合從用戶態拷貝到內核態,這個開銷在fd不少時會很大;同時每次調用select都須要在內核遍歷傳遞進來的全部fd,這個開銷在fd不少時也很大;select支持的文件描述符數量過小了,默認是1024。
select和poll都須要在返回後,經過遍歷文件描述符來獲取已經就緒的socket。事實上,同時鏈接的大量客戶端在一時刻可能只有不多的處於就緒狀態,所以隨着監視的描 述符數量的增加,其效率也會線性降低。
epoll支持一個進程打開大數目的socket描述符(FD);.IO效率不隨FD數目增長而線性降低;.使用mmap加速內核與用戶空間的消息傳遞。
select/poll每次調用時都要傳遞。你所要監控的全部socket給select/poll系統調用,這意味着須要將用戶態的socket列表copy到內核態,若是以萬計的句柄會致使每次都要copy幾十幾百KB的內存到內核態,很是低效。而咱們調用epoll_wait時就至關於以往調用select/poll,可是這時卻不用傳遞socket句柄給內核,由於內核已經在epoll_ctl中拿到了要監控的句柄列表。