首页 > 代码库 > poll 使用示例
poll 使用示例
poll()函数:
这个函数是某些Unix系统提供的用于执行与select()函数同等功能的函数,下面是这个函数的声明:
#include <poll.h>int poll(struct pollfd fds[], nfds_t nfds, int timeout);
参数说明:
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;
pollfd的结构:
struct pollfd {int fd; /*文件描述符*/short events; /* 等待的需要测试事件 */short revents; /* 实际发生了的事件,也就是返回结果 */};
使用poll来实现TCP回射服务器
例子代码源自UNIX网络编程tcpcliserv/tcpcliservpoll01.c
/* include fig01 */#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#endifintmain(int argc, char **argv){ int i, maxi, listenfd, connfd, sockfd; int nready; ssize_t n; char buf[MAXLINE]; socklen_t clilen; struct pollfd client[OPEN_MAX]; struct sockaddr_in cliaddr, servaddr; listenfd = Socket(AF_INET, SOCK_STREAM, 0);//监听fd bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); Listen(listenfd, LISTENQ); client[0].fd = listenfd; client[0].events = POLLRDNORM; for (i = 1; i < OPEN_MAX; i++) client[i].fd = -1; /* -1 indicates available entry */ maxi = 0; /* max index into client[] array *//* end fig01 *//* include fig02 */ for ( ; ; ) { nready = Poll(client, maxi+1, -1);//maxi表示client数组大小 if (client[0].revents & POLLRDNORM) { /* *new client connection *每次有新连接都会执行这个if循环,然后将新添加的链接调用accept来接受链接 */ clilen = sizeof(cliaddr); connfd = Accept(listenfd, (SA *) &cliaddr, &clilen);//accept函数返回了一个socketfd,#ifdef NOTDEF printf("new client: %s\n", Sock_ntop((SA *) &cliaddr, clilen));#endif for (i = 1; i < OPEN_MAX; i++)//监视connfd是否可读、可写 if (client[i].fd < 0) { client[i].fd = connfd; /* save descriptor */ break; } if (i == OPEN_MAX) err_quit("too many clients"); client[i].events = POLLRDNORM;//检测connfd是否可读 if (i > maxi) maxi = i; /* max index in client[] array */ if (--nready <= 0)/*如果除了listen的client[0]被激活,其他事件没有没有被激活则nready是1 *自减1后,为0,表示此次处理poll结束。继续下次监视。 */ continue; /* no more readable descriptors */ } for (i = 1; i <= maxi; i++) { /* 第0个元素是处理listen的,处理其余accept的所有可读的connfd */ if ( (sockfd = client[i].fd) < 0)//无效的fd continue; if (client[i].revents & (POLLRDNORM | POLLERR)) {//处理可读的connfd if ( (n = read(sockfd, buf, MAXLINE)) < 0) { if (errno == ECONNRESET) { /*4connection reset by client */#ifdef NOTDEF printf("client[%d] aborted connection\n", i);#endif Close(sockfd); client[i].fd = -1; } else err_sys("read error"); } else if (n == 0) { /*4connection closed by client */#ifdef NOTDEF printf("client[%d] closed connection\n", i);#endif Close(sockfd); client[i].fd = -1; } else Writen(sockfd, buf, n); if (--nready <= 0) break; /* no more readable descriptors */ } } }}/* end fig02 */
poll 使用示例