select服务器端的代码以及select的优缺点与多线程多进程服务器的比较

     系统提供select函数来实现多路复用输入输出模型。select系统调用是用来让我们的程序监视多个文件的状态发生变化的。程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变。关于文件句柄,其实就是一个整数:

0:代表标准输入(对应的FILE*结构是stdin)

1:是标准输出(对应的FILE*结构是stdout)

2:是标准错误(对应的FILE*结构是stderr)

函数返回值:

=0:表示等待超时

=-1:表示等待出错

>0:表示文件描述符中就绪文件描述符的个数

1、server服务器端:

  1 #include<stdio.h>                                                     
  2 #include<stdlib.h>
  3 #include<sys/types.h>
  4 #include<sys/socket.h>
  5 #include<netinet/in.h>
  6 #include<arpa/inet.h>
  7 #include<string.h>
  8 #include<fcntl.h>
  9 #include<sys/select.h>
 10 #define SIZE sizeof(fd_set)*8
 11         
 12 int fds[SIZE];
 13         
 14 int startup(const char *ip,int port)
 15 {       
 16     int sock=socket(AF_INET,SOCK_STREAM,0);
 17     if(sock<0)
 18     {   
 19     ┊   perror("socket");
 20     ┊   exit(2);

 21     }   

 22     struct sockaddr_in local;
 23     local.sin_family=AF_INET;
 24     local.sin_port=htons(port);
 25     local.sin_addr.s_addr=inet_addr(ip);
 26               
 27     if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
 28     {         
 29     ┊   perror("bind");
 30     ┊   exit(3);
 31     }         
 32     if(listen(sock,10)<0)
 33     {         
 34     ┊   perror("listen");
 35     ┊   exit(4);
 36     }         
 37     return sock;
 38 }             
 39 static void usage(const char *proc)                                   
 40 {             
 41     printf("Usage:%s[local_ip][local_port]\n",proc);
 42 }             
 43 int main(int argc,char* argv[])
 44 {           
 45     if(argc!=3)
 46     {       
 47     usage(argv[0]);
 48     return 1;
 49     }       
 50     int listen_sock=startup(argv[1],atoi(argv[2]));
 51     int nums=sizeof(fds)/sizeof(fds[0]);
 52     int i=0;
 53     for(;i<nums;i++)
 54     {       
 55     ┊   fds[i]=-1;
 56     }       
 57     fds[0]=listen_sock;
 58     while(1)
 59     {       
 60     ┊   int max_fd=-1;                                                
 61     ┊   fd_set rfds;
 62     ┊   FD_ZERO(&rfds);
 63     ┊   for(i=0;i<nums;i++)
 64     ┊   {
 65     ┊   ┊   if(fds[i]>0)
 66     ┊   ┊   {
 67     ┊   ┊   ┊   FD_SET(fds[i],&rfds);
 68     ┊   ┊   ┊   if(max_fd<fds[i])
 69     ┊   ┊   ┊   {
 70     ┊   ┊   ┊   ┊   max_fd=fds[i];
 71     ┊   ┊   ┊   }
 72     ┊   ┊   }
 73     ┊   }
 74     ┊   struct timeval timeout={1,0};
 75     ┊   switch(select(max_fd+1,&rfds,NULL,NULL,&timeout))
 76     ┊   {
 77     ┊   ┊   case 0:
 78     ┊   ┊   printf("timeout...\n");
 79     ┊   ┊   break;
 80     ┊   ┊   case -1:
 81     ┊   ┊   perror("select");                                         
 82     ┊   ┊   default:
 83     ┊   ┊   {
 84     ┊   ┊   ┊   for(i=0;i<nums;i++)
 85     ┊   ┊   ┊   {
 86     ┊   ┊   ┊   ┊   if(fds[i]==-1)
 87     ┊   ┊   ┊   ┊   {
 88     ┊   ┊   ┊   ┊   ┊   continue;                                     
 89     ┊   ┊   ┊   ┊   }
 90     ┊   ┊   ┊   ┊   if(i==0&&FD_ISSET(listen_sock,&rfds))
 91     ┊   ┊   ┊   ┊   {
 92     ┊   ┊   ┊   ┊   ┊   struct sockaddr_in client;
 93     ┊   ┊   ┊   ┊   ┊   socklen_t len= sizeof(client);
 94     ┊   ┊   ┊   ┊   ┊   int new_sock=accept(listen_sock,(struct           sockaddr*)&client,&len);
 95     ┊   ┊   ┊   ┊   ┊   if(new_sock<0)
 96     ┊   ┊   ┊   ┊   ┊   {
 97     ┊   ┊   ┊   ┊   ┊   ┊   perror("accept");
 98     ┊   ┊   ┊   ┊   ┊   ┊   continue;
 99     ┊   ┊   ┊   ┊   ┊   }
100     ┊   ┊   ┊   ┊   ┊   printf("get a new client:[%s:%d\n]",              inet_ntoa(client.sin_addr),ntohs(client.sin_port));
101     ┊   ┊   ┊   ┊   ┊   int j=1;
102     ┊   ┊   ┊   ┊   ┊   for(;j<nums;j++)
103     ┊   ┊   ┊   ┊   ┊   {
104     ┊   ┊   ┊   ┊   ┊   ┊   if(fds[j]==-1)
105     ┊   ┊   ┊   ┊   ┊   ┊   {
106     ┊   ┊   ┊   ┊   ┊   ┊   ┊   break;
107     ┊   ┊   ┊   ┊   ┊   ┊   }
108     ┊   ┊   ┊   ┊   ┊   }
109     ┊   ┊   ┊   ┊   ┊   if(j==nums)
110     ┊   ┊   ┊   ┊   ┊   {
111     ┊   ┊   ┊   ┊   ┊   ┊   printf("client is full\n");
112     ┊   ┊   ┊   ┊   ┊   ┊   close(new_sock);
113     ┊   ┊   ┊   ┊   ┊   }
114     ┊   ┊   ┊   ┊   ┊   else
115     ┊   ┊   ┊   ┊   ┊   {
116     ┊   ┊   ┊   ┊   ┊   ┊   fds[i]=new_sock;
117     ┊   ┊   ┊   ┊   ┊   }
118     ┊   ┊   ┊   ┊   }
119     ┊   ┊   ┊   ┊   else if(i!=0&&FD_ISSET(fds[i],&rfds))
120     ┊   ┊   ┊   ┊   {
121     ┊   ┊   ┊   ┊   ┊   char buf[1024];                               
122     ┊   ┊   ┊   ┊   ┊   ssize_t s=read(fds[i],buf,sizeof(buf)-1);
123     ┊   ┊   ┊   ┊   ┊   if(s>0)
124     ┊   ┊   ┊   ┊   ┊   {
125     ┊   ┊   ┊   ┊   ┊   ┊   buf[s]=0;
126     ┊   ┊   ┊   ┊   ┊   ┊   printf("client#%s\n",buf);
127     ┊   ┊   ┊   ┊   ┊   }
128     ┊   ┊   ┊   ┊   ┊   else
129     ┊   ┊   ┊   ┊   ┊   {
130     ┊   ┊   ┊   ┊   ┊   ┊   perror("read");
131     ┊   ┊   ┊   ┊   ┊   ┊   close(fds[i]);
132     ┊   ┊   ┊   ┊   ┊   ┊   fds[i]=-1;
133     ┊   ┊   ┊   ┊   ┊   }
134     ┊   ┊   ┊   ┊   }
135     ┊   ┊   ┊   ┊   else
136                                {       
137         
138                                }       
139     ┊   ┊   ┊   }
140     ┊   ┊   }
141     ┊   ┊   break;
142     ┊   }                                                             
143     }   
144     return 0;
145 }  

运行结果:

     

2、client客户端:

  1 #include<stdio.h> 
  2 #include<sys/types.h> 
  3 #include<netinet/in.h> 
  4 #include<arpa/inet.h> 
  5 #include<sys/socket.h> 
  6 #include<stdlib.h> 
  7 #include<string.h> 
  8 #include<strings.h> 
  9 #include<sys/stat.h> 
 10 #include<unistd.h> 
 11                  
 12 static void Usage(char *proc) 
 13 {                
 14     printf("Usage:%s[ip][port]\n"); 
 15 }                
 16 int main(int argc,char*argv[]) 
 17 {                
 18     if(argc!=3)       
 19     {            
 20        Usage(argv[0]); 
 21        return 1;
 22     }     
 23     int sock=socket(AF_INET,SOCK_STREAM,0);
 24     struct sockaddr_in peer;
 25     peer.sin_family=AF_INET;
 26     peer.sin_port=htons(atoi(argv[2]));
 27     peer.sin_addr.s_addr=inet_addr(argv[1]);
 28     peer.sin_port=htons(atoi(argv[2]));
 29     peer.sin_addr.s_addr=inet_addr(argv[1]);
 30     if(connect(sock,(struct sockaddr*)&peer,sizeof(peer))<0)
 31     {     
 32     ┊   perror("connect");
 33     ┊   return 2;
 34     }     
 35     char buf[1024];
 36     //int sfd=dup(STDOUT_FILENO);
 37     while(1)
 38     {     
 39     ┊   printf("Please enter:");                                      
 40     ┊   fflush(stdout);
 41     ┊   ssize_t s=read(0,buf,sizeof(buf)-1);
 42     ┊   int sfd=dup(STDOUT_FILENO);
 43     ┊   if(s>0)
 44     ┊   {      
 45     ┊   ┊   buf[s-1]=0;
 46     ┊   ┊   //write(sock,buf,strlen(buf));
 47     ┊   ┊   //shuchuchongdingxiang
 48     ┊   ┊   //close(1);
 49     ┊   ┊   //int new_fd=dup(sock);
 50     ┊   ┊   int new_fd=dup2(sock,1);
 51     ┊   ┊   if(new_fd==-1)
 52     ┊   ┊   { 
 53     ┊   ┊   ┊   perror("dup()");
 54     ┊   ┊   ┊   return -1;
 55     ┊   ┊   } 
 56     ┊   ┊   printf("%s",buf);
 57     ┊   ┊   fflush(stdout);
 58     ┊   ┊   //huifu stdout
 59     ┊   ┊   dup2(sfd,STDOUT_FILENO);
 60     ┊   ┊   ssize_t  _s=read(sock,buf,sizeof(buf)-1);
 61     ┊   ┊   if(_s>0)
 62     ┊   ┊   {
 63     ┊   ┊   ┊   buf[_s]=0;
 64     ┊   ┊   ┊   printf("server#%s\n",buf);
 65     ┊   ┊   }
 66     ┊   }
 67     }   
 68     close(sock);
 69     return 0;
 70 }                                                                     

3、总结:select服务器的优缺点与多进程/多线程服务器进行对比: 
使用select注意事项: 
1>要将sock_fd加入到maxfd+1中,要不就无法检测到网络连接,会一直阻塞在select语句 
2>通过存储每次连接的描述符,设置FD_SET函数,在遍历的去判断FD_ISSET处理。 
3>我们可以看到select每次有数据到来时,需要遍历的去寻找所有可用的描述符,来判断其是否满足处理的条件。 
4>select的通知机制,轮询的去查看是否在maxfd+1内有满足条件的描述符  

与多进程/多线程服务器进行对比 它的优点在于: 
1)不需要建立多个线程、进程就可以实现一对多的通信。 
2)可以同时等待多个文件描述符,效率比起多进程多线程来说要高很多。 
3)select()的可移植性更好,在某些Unix系统上不支持poll() 
4)select() 对于超时值提供了更好的精度:微秒,而poll是毫秒

与多进程/多线程服务器进行对比 它的缺点在于: 

1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大 ,循环次数有点多; 
2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大 。 
3)select支持的文件描述符数量太小了,默认是1024;


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值