Linux select服务器

简介

  系统提供select函数来实现多路复用输入/输出模型。select系统调用是用来让我们的程序监视多个文件句柄的状态变化的。程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变。关于文件句柄,其实就是一个整数,我们最熟悉的句柄是0、1、2三个,0是标准输入,1是标准输出,2是标准错误输出。0、1、2是整数表示的,对应的FILE *结构的表示就是stdin、stdout、stderr。
  对应的select函数如下

 #include <sys/select.h>
 int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
 void FD_CLR(int fd, fd_set *set);//将制定位清零
 int  FD_ISSET(int fd, fd_set *set);//判断指定位是否被设置
 void FD_SET(int fd, fd_set *set);//设置指定位
 void FD_ZERO(fd_set *set);//全部清空

程序代码

我们需要编写两个C来实现我们select服务器的建立和验证
首先我们先写出服务器建立的代码

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<unistd.h>
  4 #include<sys/select.h>
  5 #include<sys/socket.h>
  6 #include<sys/types.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 #include<string.h>
 10 
 11 static void usage(char* arg)
 12 {
 13     printf("%s[local_ip][local_port]",arg);
 14 }
 15 int starup(char* ip,int port)
 16 {
 17     int sock = socket(AF_INET,SOCK_STREAM,0);
 18     if(sock < 0)
 19     {
 20         perror("socket");
 21         exit(2);
 22     }
 23     struct sockaddr_in server;
 24     server.sin_family = AF_INET;
 25     server.sin_port = htons(port);
 26     server.sin_addr.s_addr = inet_addr(ip);
 27     int opt = 1;
 28     setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
 29     if(bind(sock,(struct sockaddr*)&server,sizeof(server)) < 0)
 30     {
 31         perror("bind");
 32         exit(3);
 33     }
 34     if(listen(sock,10)<0)
 35     {
 36         perror("listen");
 37         exit(4);
 38     }
 39     return sock;
 40 }
 41 
 42 int rfds_array[sizeof(fd_set) * 8];
 43 int write_array[sizeof(fd_set) * 8];
 44 int main(int argc,char * argv[])
 45 {
 46     if(argc != 3)
 47     {
 48         usage(argv[0]);
 49         return 1;
 50     }
 51     int listen_sock = starup(argv[1],atoi(argv[2]));
 52     int nums = 8 * sizeof(fd_set);
 53     fd_set read_set;
 54     fd_set write_set;
 55     rfds_array[0] = listen_sock;
 56     write_array[0] = -1;
 57     int i = 1;
 58     for(;i < nums;++i)
 59     {
 60         rfds_array[i] = -1;
 61         write_array[i] = -1;
 62 
 63     }
 64     while(1)
 65     {
 66         FD_ZERO(&write_set);
 67         FD_ZERO(&read_set);
 68         int max_fd = -1;
 69         for(i = 0; i < nums; ++i)
 70         {
 71             if(rfds_array[i] < 0)
 72                 continue;
 73 
 74             if(max_fd < rfds_array[i])
 75                 max_fd = rfds_array[i];
 76             FD_SET(rfds_array[i],&read_set);
  78         }
 79         int ret = select(max_fd + 1,&read_set,&write_set,NULL,NULL);
 80         if(ret > 0)
 81         {
 82             for(i=0;i < nums; ++i)
 83             {
 84                 if(i == 0 && FD_ISSET(listen_sock,&read_set))
 85                 {
 86 
 87                     struct sockaddr_in client;
 88                     socklen_t len = sizeof(client);
 89                     int new_sock = accept(listen_sock,(structsockaddr*)&client,&len);
 90                     if(new_sock <= 0)
 91                     {
 92                         perror("accept");
 93 
 94                     }
 95                     else
 96                     {
 97                         int j = 1;
 98                         for(; j < nums ; ++j)
 99                         {
100 
101                             if(rfds_array[j] == -1)
102                                 break;
103 
104                         }
105                         if(j < nums)
106                         {
107                             rfds_array[j] = new_sock;
108 
109                         }
110                         else
111                         {
112                             printf("fd_Set is full\n");
113                             close(new_sock);
114                             continue;
115                         }
116                          printf("new client come %s %d\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
117                          for(j = 0; j < nums ; ++j)
118                          {
119                              if(write_array[j] == -1)
120                                  break;
121                          }
122                          if(j < nums)
123                              write_array[j] = new_sock;
124                          else
125                          {
126                              printf("commot write\n");
127                          }
128                     }
129             }
130                 else if(i > 0 && FD_ISSET(rfds_array[i],&read_set))
131                 {
132                     char buf[1024];
133                     ssize_t s = read(rfds_array[i],buf,sizeof(buf) - 1);
134                     if(s == 0)
135                     {
136                         printf("client is quit....\n");
137                         close(rfds_array[i]);
138                         int j = 0;
139                         for(;j < nums; ++j)
140                         {
141                             if(write_array[j] == rfds_array[i])
142                                 break;
143                         }
144                         if(j < nums)
145                             write_array[j] = -1;
146                         rfds_array[i] = -1;
147                         continue;
148                     }
149                     else if (s < 0)
150                     {
151                         perror("read");
152                         close(rfds_array[i]);
153                         rfds_array[i] = -1;
154                         continue;
155                     }
156                     else
157                     {
158                         buf[s] = 0;
159                         // printf("%s %d:",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
160                          printf("%s\n",buf);
161 
162 
163                     }
164                 }
165                  if(write_array[i] != -1 && FD_ISSET(write_array[i],&write_set))
166                  {
167                      char * buf = "hello hhh";
168                      printf("%s\n",buf);
169                      write(write_array[i],buf,strlen(buf));
170                  }
171             }
172         }
173 
174         else if (ret == 0)
175         {
176             printf("no ready.\n");
177         }
178         else
179         {
180             perror("select");
181             return 5;
182         }
183 
184     }
185     return 0;
186 }


接下来我们建立一个测试用的client端

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

相关描述

  理解select模型的关键在于理解fd_set,为说明方便,取fd_set长度为1字节,fd_set中的每一bit可以对应一个⽂文件描述符fd。则1字节长的fd_set最⼤大可以对应8个fd。实际上就是位图
(1)执⾏行fd_set set; FD_ZERO(&set);则set⽤用位表⽰示是0000,0000。
(2)若fd=5,执⾏行FD_SET(fd,&set);后set变为0001,0000(第5位置为1)
(3)若再加入fd=2,fd=1,则set变为0001,0011
(4)执行select(6,&set,0,0,0)阻塞等待
(5)若fd=1,fd=2上都发生可读事件,则select返回,此时set变为0000,0011。注意:没有事件发生的fd=5被清空。

优缺点

优点:
多线程模型可以⽅方便⾼高效的解决⼩小规模的服务请求,但⾯面对⼤大规模的服务请求,多线程模型并不是最佳⽅方案。而使用select()非阻塞模型可以很好地解决该问题,只要主机允许,请求是概念上的无上限。
  
缺点:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值