引言
據(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 | 普通或優(yōu)先級帶數(shù)據(jù)可讀 | ||
| POLLRDNORM | 普通數(shù)據(jù)可讀 | ||
| POLLRDBAND | 優(yōu)先級帶數(shù)據(jù)可讀 | ||
| POLLPRI | 高優(yōu)先級數(shù)據(jù)可讀 | ||
| POLLOUT | 普通數(shù)據(jù)可寫 | ||
| POLLWRNORM | 普通數(shù)據(jù)可寫 | ||
| POLLWRBAND | 優(yōu)先級帶數(shù)據(jù)可寫 | ||
| POLLERR | 發(fā)生錯誤 | ||
| POLLHUP | 發(fā)生掛起 | ||
| POLLNVAL | 描述符不是一個打開的文件 |
我們需要記住 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ù)類型了。