IO 多路復(fù)用(三)poll 函數(shù)

引言

據(jù)說 poll 函數(shù)起源于 SVR3,最初局限于流設(shè)備。而到了 SVR4 取消了這種限制,允許 poll 工作在任何描述符上。 功能與 select 類似,不過在處理流設(shè)備時,它能夠提供額外的信息。

1.0 函數(shù)原型

#include <sys/poll.h>

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

1.1 參數(shù)

fdarray

該參數(shù)是指向一個結(jié)構(gòu)數(shù)組第一個元素的指針。每個數(shù)組元素都是一個 pollfd 結(jié)構(gòu)體,用于指定測試某個描述符 fd 的條件。我們看一下它的原型:

struct pollfd 
{
  int   fd;       /* descriptor to check */
  short events;   /* events of interest on fd */
  short revents;  /* events that occurred on fd */
};
  • fd 這個不用多說,就是描述符了。
  • events 就是我們關(guān)心的當(dāng)前描述符的事件。
  • revents 函數(shù)把當(dāng)前描述符的事件狀態(tài)結(jié)果保存在該成員中。

這就理解為,把描述符、關(guān)心的事件、事件的狀態(tài)封裝成了一個對象。這些對象組成起來就構(gòu)成了這個結(jié)構(gòu)數(shù)組。它避免了像 select 函數(shù)中間三個參數(shù)都是值-結(jié)果參數(shù)。

說明

值-結(jié)果參數(shù): 該參數(shù)在函數(shù)調(diào)用的時候作為值傳遞給函數(shù),函數(shù)執(zhí)行完畢之后將執(zhí)行結(jié)果保存到該參數(shù)中,所謂一參兩用。值-結(jié)果參數(shù)一定要傳指針。

對于 events 跟 revents 參數(shù),它們每一個都由指定某個特定條件的一位或多位構(gòu)成,下面是一些常值:

常值 是否作為 events 的輸入 是否作為 revents 結(jié)果 說明
POLLIN \bullet \bullet 普通或優(yōu)先級帶數(shù)據(jù)可讀
POLLRDNORM \bullet \bullet 普通數(shù)據(jù)可讀
POLLRDBAND \bullet \bullet 優(yōu)先級帶數(shù)據(jù)可讀
POLLPRI \bullet \bullet 高優(yōu)先級數(shù)據(jù)可讀
POLLOUT \bullet \bullet 普通數(shù)據(jù)可寫
POLLWRNORM \bullet \bullet 普通數(shù)據(jù)可寫
POLLWRBAND \bullet \bullet 優(yōu)先級帶數(shù)據(jù)可寫
POLLERR \circ \bullet 發(fā)生錯誤
POLLHUP \circ \bullet 發(fā)生掛起
POLLNVAL \circ \bullet 描述符不是一個打開的文件

我們需要記住 poll 識別三類數(shù)據(jù):普通、優(yōu)先級帶、高優(yōu)先級。

補(bǔ)充:

POLLIN 可被定義為 POLLRDNORM 和 POLLRDBAND 的邏輯或;POLLOUT 等同于 POLLWRNORM。

還要注意的是,如果是 TCP 和 UDP 套接字,一下的條件會引起 poll 返回特定的 revent (然而不性的是, POSIX 在其 poll 的定義中留了許多空洞,會造成多種方式可返回相同的條件)。

  • 所有正規(guī) TCP 數(shù)據(jù)和所有 UDP 數(shù)據(jù)都被認(rèn)為是普通數(shù)據(jù)。
  • TCP 的帶外數(shù)據(jù)被認(rèn)為是優(yōu)先級帶數(shù)據(jù)。
  • 當(dāng) TCP 連接的讀半部分關(guān)閉時(譬如收到了一個來自對端的 FIN),也被認(rèn)為是普通數(shù)據(jù),隨后的讀操作將返回 0。
  • TCP 連接存在錯誤既可認(rèn)為是普通數(shù)據(jù),也可認(rèn)為是錯誤(POLLERR)。無論哪種情況,隨后的讀操作將返回 -1,并把 errno 設(shè)置成合適的值。這可用于處理諸如接收到 RST 或發(fā)生超時等條件。
  • 在監(jiān)聽套接字上有新的連接可用既可認(rèn)為是普通數(shù)據(jù),也可認(rèn)為是優(yōu)先級數(shù)據(jù)。大多數(shù)實(shí)現(xiàn)視為普通數(shù)據(jù)。
  • 非阻塞式 connect 的完成被認(rèn)為是使相應(yīng)套接字可寫。

nfds

該參數(shù)指定了結(jié)構(gòu)數(shù)組(也就是第一個參數(shù))中元素的個數(shù)。該參數(shù)被聲明為:nfds_t 類型,對應(yīng)的其實(shí)是:unsigned int。

timeout

該參數(shù)指定了 poll 函數(shù)返回前等待多長時間。

  • INFTIM
    永久等待。
  • 0
    立刻返回,不阻塞進(jìn)程。
  • n
    指定等待毫秒數(shù) n。

INFTIM 常值被定義為一個負(fù)值。如果系統(tǒng)不能提供毫秒級精度的定時器,該值就向上舍入到最接近的支持值。

補(bǔ)充:

POSIX 規(guī)范要求在頭文件 <poll.h> 中定義 INFTIM,不過許多系統(tǒng)仍然把它定義在頭文件 <sys/stropts.h> 中。

1.2 返回值

  • 0
    運(yùn)行超時。
  • -1
    函數(shù)執(zhí)行發(fā)生錯誤。
  • n
    已經(jīng)就緒的描述符數(shù)量,即成員 revents 值非 0 的描述符數(shù)量。

如果不想關(guān)心某個描述符,只需要把該描述符對應(yīng)的 pollfd 結(jié)構(gòu)的 fd 成員設(shè)置成一個負(fù)值就可以了。poll 函數(shù)將會忽略這樣的 pollfd 結(jié)構(gòu)的 events 成員,并且返回時,將它的 revents 成員值置為 0。

2.0 注意

對于 poll 函數(shù),就不再需要關(guān)心每個進(jìn)程中最大描述符的數(shù)量之類的問題了,因?yàn)?poll 函數(shù)采用 pollfd 結(jié)構(gòu)體數(shù)組的方式傳遞給內(nèi)核,并且把傳遞數(shù)組元素的數(shù)量給內(nèi)核的責(zé)任交給了調(diào)用者。所以,內(nèi)核也就不在需要知道類似 fd_set 的固定大小的數(shù)據(jù)類型了。


參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

友情鏈接更多精彩內(nèi)容