• 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  <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
    
    #define NOTDEF
    int
    main(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(6888);
    
    	bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
    
    	listen(listenfd, 1024);
    
    	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, (struct sockaddr *) &cliaddr, &clilen);//accept函数返回了一个socketfd,
    #ifdef	NOTDEF
    			printf("new client: %s %d
    ", (struct sockaddr *) &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");
                    printf("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
    ", i);
    #endif
    						close(sockfd);
    						client[i].fd = -1;
    					} else
    						printf("read error");
    						//err_sys("read error");
    				} else if (n == 0) {
    						/*4connection closed by client */
    #ifdef	NOTDEF
    					printf("client[%d] closed connection
    ", i);
    #endif
    					close(sockfd);
    					client[i].fd = -1;
    				} else
    					//writen(sockfd, buf, n);
                        write(sockfd, buf, n);
    
    				if (--nready <= 0)
    					break;				/* no more readable descriptors */
    			}
    		}
    	}
    }
    /* end fig02 */
    
    
     
  • 相关阅读:
    树线段hdu 4508 美素数(线段树)
    自定义context自定义Dialog之Progress(二)
    实现语言C语言简单实现五子棋
    调用博客paip.基于HTML gui界面的javascript JS实现SLEEP。。
    水印控件windows phone中,制作一个自定义的密码输入框控件,含图片,有水印,星号显示
    请求网络网络编程
    调试网页PAIP HTML的调试与分析工具
    输出流输入输入输出流
    标记协议http协议与XML书写规范及解析技术
    描述算法10673 Play with Floor and Ceil
  • 原文地址:https://www.cnblogs.com/pang1567/p/4122729.html
Copyright © 2020-2023  润新知