poll()函數:這個(gè)函數是某些Unix系統提供的用于執行與select()函數同等功能的函數,下面是這個(gè)函數的聲明:
#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
參數說(shuō)明:
fds:是一個(gè)struct pollfd結構類(lèi)型的數組,用于存放需要檢測其狀態(tài)的Socket描述符;每當調用這個(gè)函數之后,系統不會(huì )清空這個(gè)數組,操作起來(lái)比較方便;特別是對于socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點(diǎn)與select()函數不同,調用select()函數之后,select()函數會(huì )清空它所檢測的socket描述符集合,導致每次調用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數適合于只檢測一個(gè)socket描述符的情況,而poll()函數適合于大量socket描述符的情況;
nfds:nfds_t類(lèi)型的參數,用于標記數組fds中的結構體元素的總數量;
timeout:是poll函數調用阻塞的時(shí)間,單位:毫秒;
返回值:
>0:數組fds中準備好讀、寫(xiě)或出錯狀態(tài)的那些socket描述符的總數量;
==0:數組fds中沒(méi)有任何socket描述符準備好讀、寫(xiě),或出錯;此時(shí)poll超時(shí),超時(shí)時(shí)間是timeout毫秒;換句話(huà)說(shuō),如果所檢測的socket描述符上沒(méi)有任何事件發(fā)生的話(huà),那么poll()函數會(huì )阻塞timeout所指定的毫秒時(shí)間長(cháng)度之后返回,如果timeout==0,那么poll() 函數立即返回而不阻塞,如果timeout==INFTIM,那么poll() 函數會(huì )一直阻塞下去,直到所檢測的socket描述符上的感興趣的事件發(fā)生是才返回,如果感興趣的事件永遠不發(fā)生,那么poll()就會(huì )永遠阻塞下去;
A timeout of INFTIM means** wait indefinitely.
-1: poll函數調用失敗,同時(shí)會(huì )自動(dòng)設置全局變量errno;
如果待檢測的socket描述符為負值,則對這個(gè)描述符的檢測就會(huì )被忽略,也就是不會(huì )對成員變量events進(jìn)行檢測,在events上注冊的事件也會(huì )被忽略,poll()函數返回的時(shí)候,會(huì )把成員變量revents設置為0,表示沒(méi)有事件發(fā)生;
另外,poll() 函數不會(huì )受到socket描述符上的O_NDELAY標記和O_NONBLOCK標記的影響和制約,也就是說(shuō),不管socket是阻塞的還是非阻塞的,poll()函數都不會(huì )收到影響;而select()函數則不同,select()函數會(huì )受到O_NDELAY標記和O_NONBLOCK標記的影響,如果socket是阻塞的socket,則調用select()跟不調用select()時(shí)的效果是一樣的,socket仍然是阻塞式TCP通訊,相反,如果socket是非阻塞的socket,那么調用select()時(shí)就可以實(shí)現非阻塞式TCP通訊;
所以poll() 函數的功能和返回值的含義與 select() 函數的功能和返回值的含義是完全一樣的,兩者之間的差別就是內部實(shí)現方式不一樣,select()函數基本上可以在所有支持文件描述符操作的系統平臺上運行(如:Linux 、Unix 、Windows、MacOS等),可移植性好,而poll()函數則只有個(gè)別的的操作系統提供支持(如:SunOS、Solaris、AIX、HP提供支持,但是Linux不提供支持),可移植性差;
strust pollfd結構說(shuō)明:
typedef struct pollfd {
int fd; /* 需要被檢測或選擇的文件描述符*/
short events; /* 對文件描述符fd上感興趣的事件 */
short revents; /* 文件描述符fd上當前實(shí)際發(fā)生的事件*/
} pollfd_t;
typedef unsigned long nfds_t;
經(jīng)常檢測的事件標記: POLLIN/POLLRDNORM(可讀)、POLLOUT/POLLWRNORM(可寫(xiě))、POLLERR(出錯)
如果是對一個(gè)描述符上的多個(gè)事件感興趣的話(huà),可以把這些常量標記之間進(jìn)行按位或運算就可以了;
比如:對socket描述符fd上的讀、寫(xiě)、異常事件感興趣,就可以這樣做:struct pollfd fds;
fds[nIndex].events=POLLIN | POLLOUT | POLLERR;
當 poll()函數返回時(shí),要判斷所檢測的socket描述符上發(fā)生的事件,可以這樣做: struct pollfd fds;
檢測可讀TCP連接請求:
if((fds[nIndex].revents & POLLIN) == POLLIN){//接收數據/調用accept()接收連接請求}
檢測可寫(xiě):
if((fds[nIndex].revents & POLLOUT) == POLLOUT){//發(fā)送數據}
檢測異常:
if((fds[nIndex].revents & POLLERR) == POLLERR){//異常處理}
poll函數可用的測試值
| 常量 | 說(shuō)明 |
| POLLIN | 普通或優(yōu)先級帶數據可讀 |
| POLLRDNORM | 普通數據可讀 |
| POLLRDBAND | 優(yōu)先級帶數據可讀 |
| POLLPRI | 高優(yōu)先級數據可讀 |
| POLLOUT | 普通數據可寫(xiě) |
| POLLWRNORM | 普通數據可寫(xiě) |
| POLLWRBAND | 優(yōu)先級帶數據可寫(xiě) |
| POLLERR | 發(fā)生錯誤 |
| POLLHUP | 發(fā)生掛起 |
| POLLNVAL | 描述字不是一個(gè)打開(kāi)的文件 |
注意:后三個(gè)只能作為描述字的返回結果存儲在revents中,而不能作為測試條件用于events中。
第二個(gè)參數nfds是用來(lái)指定數組fdarray的長(cháng)度。
最后一個(gè)參數timeout是指定poll函數返回前等待多長(cháng)時(shí)間。它的取值如下:
| timeout值 | 說(shuō)明 |
| INFTIM | 永遠等待 |
| 0 | 立即返回,不阻塞進(jìn)程 |
| >0 | 等待指定數目的毫秒數 |
一個(gè)使用poll的網(wǎng)絡(luò )程序例子:
文章出處:飛諾網(wǎng)(
www.firnow.com):
http://dev.firnow.com/course/6_s ... 0100326/201427.html#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <poll.h>
#define MAX_BUFFER_SIZE 1024 /* 緩沖區大小*/
#define IN_FILES 3 /* 多路復用輸入文件數目*/
#define TIME_DELAY 6000 /* 超時(shí)時(shí)間秒數 */
#define MAX(a, b) ((a > b)?(a)
b))
int main(void)
{
struct pollfd fds[IN_FILES];
char buf[MAX_BUFFER_SIZE];
int i, res, real_read, maxfd;
/*首先按一定的權限打開(kāi)兩個(gè)源文件*/
fds[0].fd = 0;
if((fds[1].fd = open ("in1", O_RDONLY|O_NONBLOCK)) < 0)
{
printf("Open in1 error\n"
;
return 1;
}
if((fds[2].fd = open ("in2", O_RDONLY|O_NONBLOCK)) < 0)
{
printf("Open in2 error\n"
;
return 1;
}
/*取出兩個(gè)文件描述符中的較大者*/
for (i = 0; i < IN_FILES; i++)
{
fds
.events = POLLIN;
}
while(fds[0].events || fds[1].events || fds[2].events)
{
if (poll(fds, IN_FILES, TIME_DELAY) <= 0)
{
printf("oll error\n";
return 1;
}
for (i = 0; i< IN_FILES; i++)
{
if (fds.revents)
{
memset(buf, 0, MAX_BUFFER_SIZE);
real_read = read(fds.fd, buf, MAX_BUFFER_SIZE);
if (real_read < 0)
{
if (errno != EAGAIN)
{
return 1;
}
}
else if (!real_read)
{
close(fds.fd);
fds.events = 0;
}
else
{
if (i == 0)
{
if ((buf[0] == 'q') || (buf[0] == 'Q'))
{
return 1;
}
}
else
{
buf[real_read] = '\0';
printf("%s", buf);
}
} /* end of if real_read*/
} /* end of if revents */
} /* end of for */
} /*end of while */
exit(0);
}