select,poll,epoll是io多路復用技術;(阻塞+不考慮線程,進程)
應用場景:標准輸入,套接字等都可以看做I/O的一路,當任何一路上的io事件發生時,內核移交控制權給應用程序進行io事件處理;
io事件諸如:標准輸入文件描述符准備好可以讀;監聽套接字准備好,新的連接已經建立成功;已連接套接字准備好可以寫;如果io事件等待超過10秒,發生了超時事件。
select:
維護三個描述符集合:讀描述符集合,寫描述符結合,異常描述符集合。
循環過程中初始化待測試的描述符集合,調用select,當待測試的描述符上有io事件發生時,解除阻塞,調用應用程序處理io事件。
缺點:支持的描述符個數有限。
poll:
int poll(struct pollfd*fds,unsigned long nfds,int timeout)
若有就緒描述符則返回其數目,超時返回0,出錯返回-1
struct pollfd{
int fd;//文件描述符
short events;//事件性質,POLLIN表示讀事件,POLLOUT表示寫事件
short revents;//poll檢測后的返回值
};
timout為-1,調用者進程被阻塞,直到內核io事件的分發。fds為帶有事件屬性的描述符集合,將監聽套接字加入fds,表示期望內核檢測監聽套接字的連接建立完成事件。當有io事件觸發時,遍歷所有的文件描述符。
epoll:
隨着文件描述符增多,epoll的性能遠遠高於select,poll。添加兩個機制:邊緣觸發和水平觸發。epoll較poll性能提升的一點在於epoll只遍歷觸發io事件的就緒文件描述符。
int epoll_create(int size)//創建epoll實例;
int epoll_ctl(int epfd,int op,int fd,struct epoll_event*event);//向epoll實例里添加 或刪除監控文件描述符。
epfd :epoll實例描述符;
op:標識刪除還是增加事件;
fd:文件描述符;
event:帶有可讀或者可寫等屬性的事件
typedef union epoll_data{
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
}epoll_data_t;
struct epoll_event{
uint32_t events;
epoll_data_t data;
};
int epoll_wait(int epfd,struct epoll_event *events,int maxevents,int timeout);
//類似select或者poll用於內核io事件分發,若無io事件,則調用者阻塞。返回值為io事件個數,無io事件返回0;
epfd:epoll實例描述符;
events待調用的事件集合;
tiimeout設置為-1,表示不超時,設置為0,表示沒有io事件發生,立即返回。
創建epoll實例后,將監聽套接字對應的io事件加入到epoll,這樣有新的連接的時候,會被感知到;當監聽套接字被觸發時,再把新的socket注冊到epoll中;
邊緣觸發和條件觸發的適用情況:
條件觸發(LT):只要滿足條件,比如有數據可讀,就一直不斷地把這個事件傳遞給用戶,比如listen_fd加入epoll時候,標識為LT;大塊數據遠遠大於緩存時。
邊緣觸發(ET):只有第一次滿足條件的時候才觸發。