函数原型
#include <poll.h>
int poll(struct pollfd fds[], nfds_t nfds, int timeout);
typedef struct pollfd {
int fd; /* 需要被检测或选择的文件描述符*/
short events; /* 对文件描述符fd上感兴趣的事件 */
short revents; /* 文件描述符fd上当前实际发生的事件*/
} pollfd_t;
typedef unsigned long nfds_t;
参数说明:
fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;
nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;
timeout:是poll函数调用阻塞的时间,单位:毫秒;
返回值:
>0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;
==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒;换句话说,如果所检测的socket描述符上没有任何事件发生的话,那么poll()函数会阻塞timeout所指定的毫秒时间长度之后返回,如果timeout==0,那么poll() 函数立即返回而不阻塞,如果timeout==INFTIM,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;
-1: poll函数调用失败,同时会自动设置全局变量errno;
特殊说明
如果待检测的socket描述符为负值,则对这个描述符的检测就会被忽略,也就是不会对成员变量events进行检测,在events上注册的事件也会被忽略,poll()函数返回的时候,会把成员变量revents设置为0,表示没有事件发生;
另外,poll() 函数不会受到socket描述符上的O_NDELAY标记和O_NONBLOCK标记的影响和制约,也就是说,不管socket是阻塞的还是非阻塞的,poll()函数都不会收到影响;而select()函数则不同,select()函数会受到O_NDELAY标记和O_NONBLOCK标记的影响,如果socket是阻塞的socket,则调用select()跟不调用select()时的效果是一样的,socket仍然是阻塞式TCP通讯,相反,如果socket是非阻塞的socket,那么调用select()时就可以实现非阻塞式TCP通讯;
所以poll() 函数的功能和返回值的含义与 select() 函数的功能和返回值的含义是完全一样的,两者之间的差别就是内部实现方式不一样,select()函数基本上可以在所有支持文件描述符操作的系统平台上运行(如:Linux 、Unix 、Windows、MacOS等),可移植性好,而poll()函数则只有个别的的操作系统提供支持(如:SunOS、Solaris、AIX、HP提供支持,但是Linux不提供支持),可移植性差;
代码示例(转载)
服务器
#include <unistd.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> #include <poll.h> /* poll function */ #include <limits.h> #define MAXLINE 10240 #ifndef OPEN_MAX #define OPEN_MAX 40960 #endif void handle(struct pollfd* clients, int maxClient, int readyClient); int main(int argc, char **argv) { int servPort = 6888; int listenq = 1024; int listenfd, connfd; struct pollfd clients[OPEN_MAX]; int maxi; socklen_t socklen = sizeof(struct sockaddr_in); struct sockaddr_in cliaddr, servaddr; char buf[MAXLINE]; int nready; bzero(&servaddr, socklen); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(servPort); listenfd = socket(AF_INET, SOCK_STREAM, 0); if (listenfd < 0) { perror("socket error"); } int opt = 1; if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt error"); } if(bind(listenfd, (struct sockaddr *) &servaddr, socklen) == -1) { perror("bind error"); exit(-1); } if (listen(listenfd, listenq) < 0) { perror("listen error"); } clients[0].fd = listenfd; clients[0].events = POLLIN; int i; for (i = 1; i< OPEN_MAX; i++) clients[i].fd = -1; maxi = listenfd + 1; printf("pollechoserver startup, listen on port:%d\n", servPort); printf("max connection is %d\n", OPEN_MAX); for ( ; ; ) { nready = poll(clients, maxi + 1, -1); //printf("nready is %d\n", nready); if (nready == -1) { perror("poll error"); } if (clients[0].revents & POLLIN) { connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &socklen); sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port); printf(buf, ""); for (i = 0; i < OPEN_MAX; i++) { if (clients[i].fd == -1) { clients[i].fd = connfd; clients[i].events = POLLIN; break; } } if (i == OPEN_MAX) { fprintf(stderr, "too many connection, more than %d\n", OPEN_MAX); close(connfd); continue; } if (i > maxi) maxi = i; --nready; } handle(clients, maxi, nready); } } void handle(struct pollfd* clients, int maxClient, int nready) { int connfd; int i, nread; char buf[MAXLINE]; if (nready == 0) return; for (i = 1; i< maxClient; i++) { connfd = clients[i].fd; if (connfd == -1) continue; if (clients[i].revents & (POLLIN | POLLERR)) { nread = read(connfd, buf, MAXLINE);//读取客户端socket流 if (nread < 0) { perror("read error"); close(connfd); clients[i].fd = -1; continue; } if (nread == 0) { printf("client close the connection"); close(connfd); clients[i].fd = -1; continue; } write(connfd, buf, nread);//响应客户端 if (--nready <= 0)//没有连接需要处理,退出循环 break; } } }
客户端
#include <unistd.h> #include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <netdb.h> /*gethostbyname function */ #include <stdlib.h> #include <errno.h> #include <stdio.h> #include <string.h> #define MAXLINE 1024 void handle(int connfd); int main(int argc, char **argv) { char * servInetAddr = "127.0.0.1"; int servPort = 6888; char buf[MAXLINE]; int connfd; struct sockaddr_in servaddr; if (argc == 2) { servInetAddr = argv[1]; } if (argc == 3) { servInetAddr = argv[1]; servPort = atoi(argv[2]); } if (argc > 3) { printf("usage: echoclient <IPaddress> <Port>\n"); return -1; } connfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(servPort); inet_pton(AF_INET, servInetAddr, &servaddr.sin_addr); if (connect(connfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) { perror("connect error"); return -1; } printf("welcome to echoclient\n"); handle(connfd); /* do it all */ close(connfd); printf("exit\n"); exit(0); } void handle(int sockfd) { char sendline[MAXLINE], recvline[MAXLINE]; int n; for (;;) { if (fgets(sendline, MAXLINE, stdin) == NULL) { break;//read eof } /* //也可以不用标准库的缓冲流,直接使用系统函数无缓存操作 if (read(STDIN_FILENO, sendline, MAXLINE) == 0) { break;//read eof } */ n = write(sockfd, sendline, strlen(sendline)); n = read(sockfd, recvline, MAXLINE); if (n == 0) { printf("echoclient: server terminated prematurely\n"); break; } write(STDOUT_FILENO, recvline, n); //如果用标准库的缓存流输出有时会出现问题 //fputs(recvline, stdout); } }