____________________________________________
poll提供的功能與select類似,與select在本質上沒有多大差别,管理多個描述符也是進行輪詢,但poll比select的優點是,不限制所能監視的描述符的數目,但随着所監視描述符的數目的增加,性能也會下降
函數原型:
#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
傳回值:成功時,poll()傳回結構體中revents域不為0的檔案描述符個數;如果在逾時前沒有任何事件發生,傳回0;失敗傳回-1
參數:
fds:結構體指針,該結構體結構如下:
struct pollfd{
int fd; //所感興趣的檔案描述符
short events; //用于指定等待的事件
short revents; //用于指定poll傳回時,在該檔案描述符上實際發生了的事件
};
每一個pollfd結構體制定了一個被監視檔案描述符,可傳遞多個該結構體,訓示poll監視多個檔案描述符
nfds:要監視的描述符的個數
timeout:機關(微秒),timeout指定等待的毫秒數,無論I/O是否準備好,poll都會傳回,指定為負數值表示無限逾時,使poll()一直挂起直到一個指定事件發生;timeout為0訓示poll調用立即傳回并列出準備好I/O的檔案描述符,但并不等待其它的事件,立即傳回
events域中請求的任何事件都可能在revents域中傳回。合法的事件如下:
POLLIN 有資料可讀
POLLPRI 有緊迫資料可讀
POLLOUT 寫資料不會導緻阻塞
POLLRDNORM 有普通資料可讀。
POLLRDBAND 有優先資料可讀。
POLLWRNORM 寫普通資料不會導緻阻塞。
POLLWRBAND 寫優先資料不會導緻阻塞。
POLLMSGSIGPOLL 消息可用。
此外,revents域中還可能傳回下列事件:
POLLER 指定的檔案描述符發生錯誤。
POLLHUP 指定的檔案描述符挂起事件。
POLLNVAL 指定的檔案描述符非法。
這些事件在events域中無意義,因為它們在合适的時候總是會從revents中傳回。
POLLIN | POLLPRI等價于select()的讀事件,POLLOUT |POLLWRBAND等價于select()的寫事件。POLLIN等價于POLLRDNORM |POLLRDBAND,而POLLOUT則等價于POLLWRNORM。例如,要同時監視一個檔案描述符是否可讀和可寫,我們可以設定 events為POLLIN |POLLOUT。在poll傳回時,我們可以檢查revents中的标志,對應于檔案描述符請求的events結構體。如果POLLIN事件被設定,則檔案描述符可以被讀取而不阻塞。如果POLLOUT被設定,則檔案描述符可以寫入而不導緻阻塞。這些标志并不是互斥的:它們可能被同時設定,表示這個檔案描述符的讀取和寫入操作都會正常傳回而不阻塞。
示例代碼如下:
編寫一個echo server程式,功能是用戶端向伺服器發送資訊,伺服器接收輸出并原樣發送回給用戶端,用戶端接收到輸出到終端
server_poll.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#define _BLOCKLOG_ 6
void usage(char *_proc)
{
printf("%s [ip] [port]\n",_proc);
}
int create(char *_ip,int _port)
{
int listen_fd=socket(AF_INET,SOCK_STREAM,0);
if(listen_fd<0){
perror("socket");
exit(1);
}
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_port=htons(_port);
local.sin_addr.s_addr=inet_addr(_ip);
struct linger lig;
int iLen;
lig.l_onoff=1;
lig.l_linger=0;
iLen=sizeof(struct linger);
setsockopt(listen_fd,SOL_SOCKET,SO_LINGER,(char *)&lig,iLen);
if(bind(listen_fd,(struct sockaddr*)&local,sizeof(local))<0){
perror("bind");
exit(2);
}
if(listen(listen_fd,_BLOCKLOG_)<0){
perror("listen");
exit(3);
}
return listen_fd;
}
int main(int args,char *argv[])
{
if(args!=3){
usage(argv[0]);
return 1;
}
char *ip=argv[1];
int port=atoi(argv[2]);
//建立監聽描述符并綁定
int listen_fd=create(ip,port);
nfds_t nfds=64;
struct pollfd fds[nfds];
//初始化描述符
int i=