码迷,mamicode.com
首页 > 其他好文 > 详细

多路复用之用poll编写服务器

时间:2016-05-27 18:43:47      阅读:256      评论:0      收藏:0      [点我收藏+]

标签: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也有相应的弊端:当同一时刻有大量客户端发来请求连接,但有只有很少的事件处于就绪状态,因此可能随着监视描述符数量的增长,效率也会降低




多路复用之用poll编写服务器

标签:include   服务器   return   结构体   events   

原文地址:http://10541559.blog.51cto.com/10531559/1783845

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!