函数原型:
函数说明:该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历一段指定的时间后才唤醒它。
参数说明:
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> int main() { struct pollfd fds[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; char buf[1024]; ssize_t _s; int i=0; int timeout=5000; while(1) { timeout=5000; switch(poll(fds,2,timeout)) { case -1://error perror("poll"); break; case 0://timeout printf("time out\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;//not need } // else if(fds[i].fd==1&&fds[i].revents&&POLLOUT) // { // strcpy(buf,"hello"); // printf("echo: %s",buf); // fds[i].revents=0;//not need // } } } break; } } return 0; }
运行截图:
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_ 64 static void usage(const char* proc) { printf("%s [ip][port]\n",proc); } static int start(char* ip,int port) { //1.create a socket int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } //2.bind struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(port); local.sin_addr.s_addr=inet_addr(ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(2); } //3.set listen state if(listen(sock,_BACKLOG_)<0) { perror("listen"); exit(3); } return sock; } int main(int argc,char* argv[]) { if(argc!=3) { usage(argv[0]); return 1; } int _port=atoi(argv[2]); char* _ip=argv[1]; //listen_sock_fd int listen_sock=start(_ip,_port); struct pollfd polls[_SIZE_];//struct pollfd arrays int index=0;//effective fdnum int timeout=5000;//millseconds int i=0;//index polls[0].fd=listen_sock; polls[0].events=POLLIN; polls[0].revents=0; int max_num=1; for(i=1;i<_SIZE_;++i) { polls[i].fd=-1; } char buf[1024]; ssize_t _s=0; struct sockaddr_in remote;//accept socklen_t len=sizeof(remote); while(1) { //new start //timeout=5000; switch(poll(polls,max_num,timeout)) { case 0://timeout printf("time out...\n"); break; case -1://error perror("poll"); break; default://normal { for(i=0;i<max_num;++i) { if(polls[i].fd==listen_sock&&(polls[i].revents&\ POLLIN)) { printf("get a connect\n"); int new_sock=accept(listen_sock,\ (struct sockaddr*)&remote,&len); if(new_sock<0) { perror("accept"); continue; } int j=1;//0 is listensock for(;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; } else if(polls[i].fd>0&&(polls[i].revents&\ POLLIN))//read ready { _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;//not need } else if(_s==0)//client close { close(polls[i].fd); polls[i].fd=-1; printf("client is close\n"); } } else {} } } break; } } for(i=0;i<_SIZE_;++i) { if(polls[i].fd!=-1) close(polls[i].fd); } return 0; } //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_ 64 static void usage(const char* proc) { printf("%s [ip][port]\n",proc); } static int start(char* ip,int port) { //1.create a socket int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } //2.bind struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(port); local.sin_addr.s_addr=inet_addr(ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(2); } //3.set listen state if(listen(sock,_BACKLOG_)<0) { perror("listen"); exit(3); } return sock; } int main(int argc,char* argv[]) { if(argc!=3) { usage(argv[0]); return 1; } int _port=atoi(argv[2]); char* _ip=argv[1]; //listen_sock_fd int listen_sock=start(_ip,_port); struct pollfd polls[_SIZE_];//struct pollfd arrays int index=0;//effective fdnum int timeout=5000;//millseconds int i=0;//index polls[0].fd=listen_sock; polls[0].events=POLLIN; polls[0].revents=0; ++index; for(i=1;i<_SIZE_;++i) { polls[i].fd=-1; } char buf[1024]; ssize_t _s=0; struct sockaddr_in remote;//accept socklen_t len=sizeof(remote); while(1) { //new start timeout=5000; int j=index; i=0; //消除struct pollfd中已不关心的描述符:前移,得到有效的最后一个元素下标 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=个数 { case 0://timeout printf("time out...\n"); break; case -1://error perror("poll"); break; default://normal { for(i=0;i<index;++i) { if(polls[i].fd==listen_sock&&(polls[i].revents&\ POLLIN)) { printf("get a connect\n"); int new_sock=accept(listen_sock,\ (struct sockaddr*)&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; } else if(polls[i].fd>0&&(polls[i].revents&\ POLLIN))//read ready { _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; } else if(_s==0)//client close { close(polls[i].fd); polls[i].fd=-1; printf("client is close\n"); } } else {} } } break; } } for(i=0;i<_SIZE_;++i) { if(polls[i].fd!=-1) close(polls[i].fd); } return 0; } //仿select版,用辅助数组存储,没有利用poll结构体的优点,event不清空,开销大 int main(int argc,char* argv[]) { if(argc!=3) { usage(argv[0]); return 1; } int _port=atoi(argv[2]); char* _ip=argv[1]; //listen_sock_fd int listen_sock=start(_ip,_port); struct pollfd polls[_SIZE_];//struct pollfd arrays int index=0;//effective fdnum int timeout=5000;//millseconds int i=0;//index int fds[_SIZE_]; fds[0]=listen_sock; for(i=1;i<_SIZE_;++i) { fds[i]=-1; } char buf[1024]; ssize_t _s=0; struct sockaddr_in remote;//accept socklen_t len=sizeof(remote); while(1) { index=0;//new start timeout=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)) { case 0://timeout printf("time out...\n"); break; case -1://error perror("poll"); break; default://normal { for(i=0;i<index;++i) { if(polls[i].fd==listen_sock&&(polls[i].revents&\ POLLIN)) { printf("get a connect\n"); int new_sock=accept(listen_sock,\ (struct sockaddr*)&remote,&len); if(new_sock<0) { perror("accept"); continue; } int j; 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 } else if(polls[i].fd>0&&(polls[i].revents&\ POLLIN))//read ready { _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)); } else if(_s==0)//client close { close(polls[i].fd); int j; for(j=0;j<_SIZE_;++j) { if(fds[j]==polls[i].fd) { fds[j]=-1; break; } } printf("client is close\n"); } } else {} } } break; } } for(i=0;i<_SIZE_;++i) { if(fds[i]!=-1) close(fds[i]); } return 0; } //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> void Usage(const char* proc) { printf("%s [ip][port]",proc); } int main(int argc,char* argv[]) { if(argc!=3) { Usage(argv[0]); return 1; } int client_sock=socket(AF_INET,SOCK_STREAM,0); if(client_sock<0) { perror("socket"); return 1; } struct sockaddr_in client; client.sin_family=AF_INET; client.sin_port=htons(atoi(argv[2])); client.sin_addr.s_addr=inet_addr(argv[1]); char buf[1024]; ssize_t _s; if(connect(client_sock,(struct sockaddr*)&client,sizeof(client))<0) { perror("connection"); return 2; } while(1) { printf("please enter:\n"); _s=read(0,buf,sizeof(buf)-1); if(_s>0) buf[_s]='\0'; if(strncmp(buf,"quit",4)==0) { printf("client is quit\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); return 0; }
运行截图:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。