I/O多路復用之poll


1、select的些許缺點

回憶一下 select接口 

int select(int nfdsfd_set *readfdsfd_set *writefdsfd_set *exceptfds, struct timeval *timeout);

select需要我們指定文件描述符的最大值,然后取[0,nfds)這個范圍內的值查看是在集合readfds,writefds或execptfds中,也就是說這個范圍內存在一些不是我們感興趣的文件描述符,cpu做了一些無用功,poll對她進行了改進,下面就看看poll是怎么做的。

2、poll接口

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

跟select不同的是,poll不再告知內核一個范圍,而是通過struct pollfd結構體數組精確的告知內核用戶關心哪些文件描述符(流)。參數nfds指示結構體數組的大小。timeout表示程序員的忍耐度,有三種取值:

  • 0,poll函數不阻塞
  • 整數,阻塞timeout時間
  • 負數,無限阻塞

下面來看一下struct pollfd結構體,以及其中的事件有哪些取值,及其含義

struct pollfd {

  int fd; /* an open file file descriptor */
  short events; /* requested events */
  short revents; /* returned events */
};

  • fd屬性表示一個打開的文件描述符
  • events屬性是一個輸入參數,通過bit mask的方式描述程序感興趣的事件(讀、寫)
  • revents屬性是一個傳出參數,同樣式通過bit mask的方式描述發生的事件,這個屬性的值是由內核設置的。revents的值可能是events屬性的值,也可能是POLLERR,POLLHUP,POLLNVAL的一個或多個,POLLERR,POLLHUP,POLLNVAL在events屬性中是沒有意義的。

events 和 revents能夠設置的值都定義在<poll.h>頭中,有以下幾種可能

  • POLLIN ,讀事件
  • POLLPRI,讀事件,但表示緊急數據,例如tcp socket的帶外數據
  • POLLRDNORM , 讀事件,表示有普通數據可讀     
  • POLLRDBAND , 讀事件,表示有優先數據可讀     
  • POLLOUT,寫事件
  • POLLWRNORM , 寫事件,表示有普通數據可寫
  • POLLWRBAND , 寫事件,表示有優先數據可寫            
  • POLLRDHUP (since Linux 2.6.17),Stream socket的一端關閉了連接(注意是stream socket,我們知道還有raw socket,dgram socket),或者是寫端關閉了連接,如果要使用這個事件,必須定義_GNU_SOURCE 宏。這個事件可以用來判斷鏈路是否發生異常(當然更通用的方法是使用心跳機制)。要使用這個事件,得這樣包含頭文件:
      #define _GNU_SOURCE  
      #include <poll.h>
  • POLLERR,僅用於內核設置傳出參數revents,表示設備發生錯誤
  • POLLHUP,僅用於內核設置傳出參數revents,表示設備被掛起,如果poll監聽的fd是socket,表示這個socket並沒有在網絡上建立連接,比如說只調用了socket()函數,但是沒有進行connect。
  • POLLNVAL,僅用於內核設置傳出參數revents,表示非法請求文件描述符fd沒有打開

 

poll函數返回值,有三種可能

  • positive number,表示struct pollfd結構體數組中有多少個非0的revents,換句話說,就是這一次調用poll發生哪些事件。
  • 0,表示timeout到時,並且沒有文件描述符准備好
  • -1,內部發生了錯誤,errno將會被設置

當poll返回值為-1時,表示poll出錯,errno將被設置,errno的取值有4種可能

  • EFAULT ,參數struct pollfd結構體數組不在用戶地址空間,比如傳入的參數nfds比實際的數組要大。
  • EINTR ,被信號中斷.
  • EINVAL , nfds 超出了RLIMIT_NOFILE值.
  • ENOMEM ,內核沒有足夠的內存裝載struct pollfd結構體數組

3、poll與select參數對比

使用poll()和select()不一樣,你不需要顯式地請求異常情況報告。
POLLIN | POLLPRI等價於select()的讀事件,POLLOUT |POLLWRBAND等價於select()的寫事件。POLLIN等價於POLLRDNORM |POLLRDBAND,而POLLOUT則等價於POLLWRNORM。

4、poll原理

poll的功能和select的功能一樣,只不過是參數稍微不同,poll的底層原理也和select差不多,就不多說了,I/O多路復用之select


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM