poll的用法和select区别并不是很大。非常像。最大文件描述符数量我直接使用FD_SETSIZE了。
比起select来,代码少了一些。也方便了些。使用方式的区别也并不大。但是比select要灵活了
服务端
#include <stdio.h> #include "unp.h" int main() { int i,maxi,maxfd,listenfd,clifd; int n,readycnt; char buff[MAXLINE]; struct pollfd client[FD_SETSIZE]; //服务端套接口的创建,绑定,监听 struct sockaddr_in serAddr; bzero(&serAddr,sizeof(serAddr)); serAddr.sin_family=AF_INET; serAddr.sin_port=htons(SERV_PORT); serAddr.sin_addr.s_addr=htonl(INADDR_ANY); listenfd=Socket(AF_INET,SOCK_STREAM,0); Bind(listenfd,(SA*)&serAddr,sizeof(serAddr)); Listen(listenfd,LISTENQ); //poll添加监听这个服务端端口的套接口 client[0].fd=listenfd; client[0].events=POLLRDNORM; //后面的全部初始化为-1 for(i=1;i<FD_SETSIZE;i++){ client[i].fd=-1; } maxi=0; for(;;){ readycnt=Poll(client,maxi+1,INFTIM); //开始阻塞,等待就绪的数据 if(client[0].revents&POLLRDNORM){ //第一个是单独加的服务端端口监控的套接口,如果有数据就绪,就是直接接收客户端连接 clifd=Accept(listenfd,(SA*)NULL,NULL); //接收客户端连接 for(i=0;i<FD_SETSIZE;i++){ //找到一个空的位置 if(client[i].fd<0) break; } if(i>=FD_SETSIZE) //没有位置了,放不下就直接报错咯 err_quit("too many clients"); client[i].fd=clifd; //记录这个客户端连接 client[i].events=POLLRDNORM; //添加读的监控 if(i>maxi) //修改最大索引 maxi=i; if(--readycnt<=0) //如果没有其他就绪的。就不用往后走了 continue; } for(i=1;i<=maxi;i++){ //遍历所有客户端连接 if(client[i].fd<0) //空数据的跳过 continue; if(client[i].revents&(POLLRDNORM|POLLERR)){ //因为有些实现再一个连接上接收到RST时返回的是POLLERR事件。所以这两种事件触发。我们都read下 if((n=Read(client[i].fd,buff,MAXLINE))<=0){ //如果失败的错误处理 if(n==0){ Close(client[i].fd); client[i].fd=-1; } else if(errno==ECONNRESET){ Close(client[i].fd); client[i].fd=-1; } else err_quit("read err"); } else Writen(client[i].fd,buff,n); //成功就直接写入返回数据 if(--readycnt<=0) //就绪队列完成就结束循环 break; } } } }