函数原型:

函数说明:该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒它。

参数说明:

fds:是一个struct pollfd结构类型的数组,用于存放需要检测其状态的Socket描述符;

每当调用这个函数之后,系统不会清空这个数组,操作起来比较方便;特别是对于socket连接比较多的情况下,在一定程度上可以提高处理的效率;这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中;因此,select()函数适合于只检测一个socket描述符的情况,而poll()函数适合于大量socket描述符的情况;

nfds:nfds_t类型的参数,用于标记数组fds中的结构体元素的总数量;

timeout:是poll函数阻塞的时间,单位:毫秒;

如果timeout==0,那么poll() 函数立即返回而不阻塞

如果timeout==INFTIM,即负数,那么poll() 函数会一直阻塞下去,直到所检测的socket描述符上的感兴趣的事件发生是才返回,如果感兴趣的事件永远不发生,那么poll()就会永远阻塞下去;

poll()函数会以轮询方式在timeout所指定的毫秒时间长度之后返回

返回值:

>0:数组fds中准备好读、写或出错状态的那些socket描述符的总数量;

==0:数组fds中没有任何socket描述符准备好读、写,或出错;此时poll超时,超时时间是timeout毫秒

-1: poll函数调用失败,同时会自动设置全局变量errno;

struct pollfd中event的设置参数:


实现IO复用:关心输入输出条件就绪

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<poll.h>intmain(){structpollfdfds[2];fds[0].fd=0;fds[0].events=POLLIN;fds[0].revents=0;fds[1].fd=1;fds[1].events=POLLOUT;fds[1].revents=0;charbuf[1024];ssize_t_s;inti=0;inttimeout=5000;while(1){timeout=5000;switch(poll(fds,2,timeout)){case-1://errorperror("poll");break;case0://timeoutprintf("timeout\n");break;default:{for(i=0;i<2;++i){if(fds[i].fd==0&&fds[i].revents&POLLIN){_s=read(0,buf,sizeof(buf)-1);if(_s>0){buf[_s]='\0';if(strncmp(buf,"quit",4)==0){close(fds[i].fd);exit(0);}printf("echo:%s",buf);}//fds[i].revents=0;//notneed}//elseif(fds[i].fd==1&&fds[i].revents&&POLLOUT)//{//strcpy(buf,"hello");//printf("echo:%s",buf);//fds[i].revents=0;//notneed//}}}break;}}return0;}

运行截图:

TCP通信:监听socket

server:

创建监听套接字并初始化:调用socket,bind,listen,唯一描述符是监听描述符初始化数据结构。

阻塞于select:select等待某个事件发生或新客户连接的建立或是数据,FIN或RST的到达。

accept新连接

如果监听套接字变为可读,那么已建立一个新的连接,我们调用accept并更新相应数据结构。使用fds数组中第一个未用项记录这个已连接描述符。

检查现有连接

对于每个现有客户连接,我们要测试其描述符是否在select返回描述符集中,如果是就从该客户读取一行文本,并回显,输出。如果该客户关闭了连接,那么read将返回0,更新数据结构。

poll与select不同在于描述符存储方式不同和参数类型不同。

1.结构体数组的管理:当每次有需要关心的描述符时,将其放入结构体中,每次有无效的描述符后,将其描述符置-1,下次poll函数会忽略它。当有新的描述符加入时,从头遍历结构体,将为-1的元素设为要关心的描述符事件状态。切记:当新的描述符加到结构体数组末尾时要更新关心描述符个数,即poll第二个参数。

2.每次调用poll后,结构体元素revents会存储就绪事件状态,当每次重新调用poll之前时,系统会自己设置其为0,重新监听关心事件(不需要用户重新置0)

3.poll中参数不是输入,输出型,因此timeout,struct pollfd *fds参数不需重置,nfds看情况(参照第一点),而select函数是输入输出类型,每次调用前需重置。

//server:最终版include<stdio.h>#include<sys/socket.h>#include<sys/types.h>#include<netinet/in.h>#include<arpa/inet.h>#include<stdlib.h>#include<poll.h>#include<string.h>#include<errno.h>#define_BACKLOG_5#define_SIZE_64staticvoidusage(constchar*proc){printf("%s[ip][port]\n",proc);}staticintstart(char*ip,intport){//1.createasocketintsock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");exit(1);}//2.bindstructsockaddr_inlocal;local.sin_family=AF_INET;local.sin_port=htons(port);local.sin_addr.s_addr=inet_addr(ip);if(bind(sock,(structsockaddr*)&local,sizeof(local))<0){perror("bind");exit(2);}//3.setlistenstateif(listen(sock,_BACKLOG_)<0){perror("listen");exit(3);}returnsock;}intmain(intargc,char*argv[]){if(argc!=3){usage(argv[0]);return1;}int_port=atoi(argv[2]);char*_ip=argv[1];//listen_sock_fdintlisten_sock=start(_ip,_port);structpollfdpolls[_SIZE_];//structpollfdarraysintindex=0;//effectivefdnuminttimeout=5000;//millsecondsinti=0;//indexpolls[0].fd=listen_sock;polls[0].events=POLLIN;polls[0].revents=0;intmax_num=1;for(i=1;i<_SIZE_;++i){polls[i].fd=-1;}charbuf[1024];ssize_t_s=0;structsockaddr_inremote;//acceptsocklen_tlen=sizeof(remote);while(1){//newstart//timeout=5000;switch(poll(polls,max_num,timeout)){case0://timeoutprintf("timeout...\n");break;case-1://errorperror("poll");break;default://normal{for(i=0;i<max_num;++i){if(polls[i].fd==listen_sock&&(polls[i].revents&\POLLIN)){printf("getaconnect\n");intnew_sock=accept(listen_sock,\(structsockaddr*)&remote,&len);if(new_sock<0){perror("accept");continue;}intj=1;//0islistensockfor(;j<_SIZE_;++j){if(polls[j].fd==-1){polls[j].fd=new_sock;polls[j].events=POLLIN;polls[j].revents=0;break;}}if(j==_SIZE_){printf("full");close(new_sock);return-1;}if(j==max_num)//加入的是max_num为下标的位置,即最后max_num+=1;}elseif(polls[i].fd>0&&(polls[i].revents&\POLLIN))//readready{_s=read(polls[i].fd,buf,sizeof(buf)-1);if(_s>0){buf[_s]='\0';printf("client:%s",buf);write(polls[i].fd,buf,strlen(buf));polls[i].revents=0;//notneed}elseif(_s==0)//clientclose{close(polls[i].fd);polls[i].fd=-1;printf("clientisclose\n");}}else{}}}break;}}for(i=0;i<_SIZE_;++i){if(polls[i].fd!=-1)close(polls[i].fd);}return0;}//server:优质版#include<stdio.h>#include<sys/socket.h>#include<sys/types.h>#include<netinet/in.h>#include<arpa/inet.h>#include<stdlib.h>#include<poll.h>#include<string.h>#include<errno.h>#define_BACKLOG_5#define_SIZE_64staticvoidusage(constchar*proc){printf("%s[ip][port]\n",proc);}staticintstart(char*ip,intport){//1.createasocketintsock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");exit(1);}//2.bindstructsockaddr_inlocal;local.sin_family=AF_INET;local.sin_port=htons(port);local.sin_addr.s_addr=inet_addr(ip);if(bind(sock,(structsockaddr*)&local,sizeof(local))<0){perror("bind");exit(2);}//3.setlistenstateif(listen(sock,_BACKLOG_)<0){perror("listen");exit(3);}returnsock;}intmain(intargc,char*argv[]){if(argc!=3){usage(argv[0]);return1;}int_port=atoi(argv[2]);char*_ip=argv[1];//listen_sock_fdintlisten_sock=start(_ip,_port);structpollfdpolls[_SIZE_];//structpollfdarraysintindex=0;//effectivefdnuminttimeout=5000;//millsecondsinti=0;//indexpolls[0].fd=listen_sock;polls[0].events=POLLIN;polls[0].revents=0;++index;for(i=1;i<_SIZE_;++i){polls[i].fd=-1;}charbuf[1024];ssize_t_s=0;structsockaddr_inremote;//acceptsocklen_tlen=sizeof(remote);while(1){//newstarttimeout=5000;intj=index;i=0;//消除structpollfd中已不关心的描述符:前移,得到有效的最后一个元素下标while(i<j){while(i<j&&polls[i].fd!=-1)//从前面数第一个无效的++i;while(i<j&&polls[j].fd==-1)//从后面数第一个有效的--j;if(i<j)//复制fd{polls[i].fd=polls[j].fd;polls[i].events=POLLIN;//可不需要,因为event参数不发生变化,本程序只监听读事件polls[index].revents=0;}}index=i;//printf("%d",index);//须保证polls是有序的switch(poll(polls,index,timeout))//index表明最后一个关心的描述符在数组中下标+1=个数{case0://timeoutprintf("timeout...\n");break;case-1://errorperror("poll");break;default://normal{for(i=0;i<index;++i){if(polls[i].fd==listen_sock&&(polls[i].revents&\POLLIN)){printf("getaconnect\n");intnew_sock=accept(listen_sock,\(structsockaddr*)&remote,&len);if(new_sock<0){perror("accept");continue;}if(index==_SIZE_){printf("full");close(new_sock);return-1;}polls[index].fd=new_sock;polls[index].events=POLLIN;polls[index].revents=0;++index;}elseif(polls[i].fd>0&&(polls[i].revents&\POLLIN))//readready{_s=read(polls[i].fd,buf,sizeof(buf)-1);if(_s>0){buf[_s]='\0';printf("client:%s",buf);write(polls[i].fd,buf,strlen(buf));polls[i].revents=0;}elseif(_s==0)//clientclose{close(polls[i].fd);polls[i].fd=-1;printf("clientisclose\n");}}else{}}}break;}}for(i=0;i<_SIZE_;++i){if(polls[i].fd!=-1)close(polls[i].fd);}return0;}//仿select版,用辅助数组存储,没有利用poll结构体的优点,event不清空,开销大intmain(intargc,char*argv[]){if(argc!=3){usage(argv[0]);return1;}int_port=atoi(argv[2]);char*_ip=argv[1];//listen_sock_fdintlisten_sock=start(_ip,_port);structpollfdpolls[_SIZE_];//structpollfdarraysintindex=0;//effectivefdnuminttimeout=5000;//millsecondsinti=0;//indexintfds[_SIZE_];fds[0]=listen_sock;for(i=1;i<_SIZE_;++i){fds[i]=-1;}charbuf[1024];ssize_t_s=0;structsockaddr_inremote;//acceptsocklen_tlen=sizeof(remote);while(1){index=0;//newstarttimeout=5000;for(i=0;i<_SIZE_;++i){polls[i].fd=-1;}for(i=0;i<_SIZE_;++i){if(fds[i]!=-1){polls[index].fd=fds[i];polls[index].events=POLLIN;polls[index].revents=0;++index;}}switch(poll(polls,index,timeout)){case0://timeoutprintf("timeout...\n");break;case-1://errorperror("poll");break;default://normal{for(i=0;i<index;++i){if(polls[i].fd==listen_sock&&(polls[i].revents&\POLLIN)){printf("getaconnect\n");intnew_sock=accept(listen_sock,\(structsockaddr*)&remote,&len);if(new_sock<0){perror("accept");continue;}intj;for(j=0;j<_SIZE_;++j){if(fds[j]==-1){fds[j]=new_sock;break;}}if(j==_SIZE_){printf("full");close(new_sock);return-1;}polls[i].revents=0;//reset}elseif(polls[i].fd>0&&(polls[i].revents&\POLLIN))//readready{_s=read(polls[i].fd,buf,sizeof(buf)-1);if(_s>0){buf[_s]='\0';printf("client:%s",buf);write(polls[i].fd,buf,strlen(buf));}elseif(_s==0)//clientclose{close(polls[i].fd);intj;for(j=0;j<_SIZE_;++j){if(fds[j]==polls[i].fd){fds[j]=-1;break;}}printf("clientisclose\n");}}else{}}}break;}}for(i=0;i<_SIZE_;++i){if(fds[i]!=-1)close(fds[i]);}return0;}//client:#include<stdio.h>#include<stdlib.h>#include<errno.h>#include<sys/types.h>#include<sys/socket.h>#include<arpa/inet.h>#include<netinet/in.h>#include<string.h>voidUsage(constchar*proc){printf("%s[ip][port]",proc);}intmain(intargc,char*argv[]){if(argc!=3){Usage(argv[0]);return1;}intclient_sock=socket(AF_INET,SOCK_STREAM,0);if(client_sock<0){perror("socket");return1;}structsockaddr_inclient;client.sin_family=AF_INET;client.sin_port=htons(atoi(argv[2]));client.sin_addr.s_addr=inet_addr(argv[1]);charbuf[1024];ssize_t_s;if(connect(client_sock,(structsockaddr*)&client,sizeof(client))<0){perror("connection");return2;}while(1){printf("pleaseenter:\n");_s=read(0,buf,sizeof(buf)-1);if(_s>0)buf[_s]='\0';if(strncmp(buf,"quit",4)==0){printf("clientisquit\n");break;}write(client_sock,buf,_s);_s=read(client_sock,buf,sizeof(buf)-1);if(_s>0){buf[_s]='\0';printf("server->client:%s",buf);}}close(client_sock);return0;}

运行截图: