标签:include 服务器 return 结构体 events
poll使用一个结构体指针代替select中读事件、写事件及异常事件。
结构体组成:
events(请求事件)关心该文件描述符的什么事件
所关心的事件有:
poll函数原型:int poll(struct pollfd* fds,nfds_t nfds,int timeout)
fds:为一个struct pollfd结构体类型的数组,存放要检测其状态的socket描述符
nfds:表示结构体数组总大小
timeout:poll函数阻塞等待的时间
return val:
大于0:结构体数组中准备好读、写或出错状态的socket描述符的总数量;
等于0:结构体数组中没有任何socket描述符就绪,poll超时,超时时间是timeout毫秒
小于: poll函数调用失败
服务器端代码:(针对单客户端)
1 #include<stdio.h> 2 #include<string.h> 3 #include<sys/socket.h> 4 #include<sys/types.h> 5 #include<netinet/in.h> 6 #include<arpa/inet.h> 7 #include<errno.h> 8 #include<poll.h> 9 #include<stdlib.h> 10 #include<assert.h> 11 12 #define MAX_SIZE 64 13 #define BACK_LOG 5 14 void Usage(const char* proc) 15 { 16 printf("Usage:%s [ip] [port]\n",proc); 17 } 18 19 static int startup(char* ip,int port) 20 { 21 assert(ip); 22 int listen_sock=socket(AF_INET,SOCK_STREAM,0); 23 if(listen_sock<0) 24 { 25 perror("socket"); 26 exit(1); 27 } 28 struct sockaddr_in local; 29 local.sin_family=AF_INET; 30 local.sin_port=htons(port); 31 local.sin_addr.s_addr=inet_addr(ip); 32 socklen_t size=sizeof(local); 33 if(bind(listen_sock,(struct sockaddr*)&local,size)<0) 34 { 35 perror("bind"); 36 exit(2); 37 } 38 if(listen(listen_sock,BACK_LOG)<0) 39 { 40 perror("listen"); 41 exit(3); 42 } 43 return listen_sock; 44 } 45 int main(int argc,char* argv[]) 46 { 47 if(argc!=3) 48 { 49 Usage(argv[0]); 50 exit(1); 51 } 52 char *_ip=argv[1]; 53 int _port=atoi(argv[2]); 54 int listen_sock=startup(_ip,_port); 55 struct sockaddr_in client; 56 socklen_t size=sizeof(client); 57 struct pollfd fd_set[MAX_SIZE]; 58 fd_set[0].fd=listen_sock; 59 fd_set[0].events=POLLIN; 60 fd_set[0].revents=0; 61 char buf[1024]; 62 int max_fd=0; 63 int timeout=5000; 64 int done=0; 65 int i=1; 66 int j=0; 67 for(;i<MAX_SIZE;++i) 68 { 69 fd_set[i].fd=-1; 70 } 71 while(!done) 72 { 73 timeout=5000; 74 switch(poll(fd_set,max_fd+1,timeout)) 75 { 76 case -1: 77 perror("poll"); 78 break; 79 case 0: 80 printf("poll timeout...\n"); 81 break; 82 default: 83 { 84 for(i=0;i<MAX_SIZE;++i) 85 { 86 if(fd_set[i].fd==listen_sock && 87 (fd_set[i].revents&POLLIN)) 88 {//**判断是否为监听状态且判断它返回的哪一个就绪事件 89 int new_sock=accept(listen_sock,(struct sockaddr*)&client,&size); 90 if(new_sock<0) 91 { 92 perror("accept"); 93 return -1; 94 } 95 printf("get a new conn... [fd:%d] [ip:%s]\n", 96 new_sock,inet_ntoa(client.sin_addr)); 97 for(j=0;i<MAX_SIZE;++j) 98 { 99 if(fd_set[j].fd==-1) 100 { 101 fd_set[j].fd=new_sock; 102 fd_set[j].events=POLLIN; 103 break; 104 } 105 } 106 if(j==MAX_SIZE) 107 { 108 printf("fd_set[] is full...\n "); 109 close(new_sock); 110 exit(1); 111 } 112 if(j>max_fd) 113 { 114 max_fd=j; 115 } 116 117 }else if(fd_set[i].fd>0 &&118 (fd_set[i].revents&POLLIN)) 119 { //表示读事件是否已经就绪 120 ssize_t _size=read(fd_set[i].fd,buf,sizeof(buf)-1); 121 if(_size>0) 122 { 123 buf[_size]=‘\0‘; 124 printf("client:%s",buf); 125 write(fd_set[i].fd,buf,_size); 126 fd_set[i].revents=0; 127 } 128 else if(_size==0) 129 { 130 printf("client is closed...\n"); 131 close(fd_set[i].fd); 132 fd_set[i].fd=-1; 133 } 134 } 135 } 136 } 137 break; 138 139 } 140 } 141 142 143 return 0; 144 }
客户端代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<sys/socket.h> 4 #include<sys/types.h> 5 #include<netinet/in.h> 6 #include<arpa/inet.h> 7 #include<errno.h> 8 #include<stdlib.h> 9 #include<assert.h> 10 11 void Usage(const char* proc) 12 { 13 printf("Usage:%s [remoteip] [remotrport]\n",proc); 14 } 15 16 int main(int argc,char* argv[]) 17 { 18 if(argc!=3) 19 { 20 Usage(argv[0]); 21 exit(1); 22 } 23 int sock=socket(AF_INET,SOCK_STREAM,0); 24 if(sock<0) 25 { 26 perror("sock"); 27 exit(2); 28 } 29 char *_ip=argv[1]; 30 int _port=atoi(argv[2]); 31 struct sockaddr_in remote; 32 remote.sin_family=AF_INET; 33 remote.sin_port=htons(_port); 34 remote.sin_addr.s_addr=inet_addr(_ip); 35 socklen_t len=sizeof(remote); 36 int ret=connect(sock,(struct sockaddr*)&remote,len); 37 if(ret<0) 38 { 39 perror("connect"); 40 return -1; 41 } 42 char buf[1024]; 43 while(1) 44 { 45 memset(buf,‘\0‘,sizeof(buf)); 46 printf("please input:"); 47 fflush(stdout); 48 if(read(0,buf,sizeof(buf)-1)>0) 49 { 50 write(sock,buf,strlen(buf)); 51 } 52 53 ssize_t _size=read(sock,buf,sizeof(buf)-1); 54 if(_size>0) 55 { 56 printf("server---client:%s",buf); 57 } 58 } 59 close(sock); 60 return 0; 61 }
运行结果:
总结:(select与poll之间的区别)
select:使用三个文件描述符集(分别为读事件、写事件、异常事件)表示它们各自关心什么事件,将对应的文件描述符设置进去
它存在一定的弊端:
1.每次轮询前都要对所关心的文件描述符集进行设置及初始化(因为它们是输入输出型参数),每次都要遍历所有的文件描述符
2.它依赖文件描述符,但是文件描述符集的大小是有一定的限度的,当有大量的客户端同时请求服务器时不适宜使用
3.它的三个文件描述符集当中若有多个被修改,每次修改都要从用户态切换到内核态,内核态来负责修改文件描述符的状态变化
poll:使用一个结构体数组来代替select中的三个文件描述符集,它的大小不受限制
优化:
1.若有需要关心的文件描述符时,将它保存到结构体中,并设置该描述符所关心的事件,每次轮询完后若有无效的文件描述符时,将其描述符的状态置-1,当再次调poll函数时会忽略它
2.当有新的文件描述符时,重新遍历结构体,将出现第一个为-1的状态时,将它设置为要关心的描述符事件状态,每次有新的文件描述符加入时,更改要关心的文件描述符数量
3.调用poll函数后,结构体中的revents(返回已经就绪的事件)会存储就绪事件状态,重新调用poll之前,系统设置该状态默认其为0,重新监听关心事件
但poll也有相应的弊端:当同一时刻有大量客户端发来请求连接,但有只有很少的事件处于就绪状态,因此可能随着监视描述符数量的增长,效率也会降低
标签:include 服务器 return 结构体 events
原文地址:http://10541559.blog.51cto.com/10531559/1783845