select 模型特点
1.可监控的文件描述符个数取决与文件描述符集的大小(sizeof(fd_set) 的值)。假设:sizeof ( fd_set) = 512, 每个bit表示一个文件描述符,则支持的最大文件描述符是512*8=4096.
2.将fd加入select监控集的同时,还要再使用一个数据结构array保存select监控集中的 fd_set,一是用于再select 返回后,array作为源数据和fd_set进行FD_ISSET判断。二是select返回后会把以前加入的但并无事件发生的fd清空,则每次开始 select前都要重新从array取得fd逐一加入(FD_ZERO最先),扫描array的同时取得fd最大值maxfd,用于select的第一个 参数。
3.可见select模型必须在select前循环array(加fd,取maxfd),select返回后循环array(FD_ISSET判断是否有时间发生)。
模型的缺点
1.每次进行select都要把文件描述符集fd由用户态拷贝到内核态,这样的开销会很大。
2 实现select服务器,内部要不断对文件描述符集fd进行循环遍历,当fd很多时,开销也很大。
3.select能监控文件描述符的数量有限,一般为1024。(sizeof(fd_set) * 8 = 1024(fd_set内部是以位图表示文件描述符)
select模型的服务器
1 #include<stdio.h>
2 #include<sys/types.h>
3 #include<netinet/in.h>
4 #include<arpa/inet.h>
5 #include<string.h>
6 #include<stdlib.h>
7 #include<time.h>
8 #include<unistd.h>
9
10 int array_fds[1024];
11
12 int startup(char* ip,int port)
13 {
14 int sock = socket(AF_INET,SOCK_STREAM,0);
15 if(sock<0){
16 perror("sock");
17 exit(2);
18 }
19 int flg = 1;
20 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&flg,sizeof(flg));
21 struct sockaddr_in local;
22 local.sin_family = AF_INET;
23 local.sin_port = htons(port);
24 local.sin_addr.s_addr = inet_addr(ip);
25 if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){
26 perror("bind");
27 exit(3);
28 }
29 if(listen(sock,10)){
30 perror("listen");
31 exit(4);
32 }
33 return sock;
34 }
35 int main(int argc,char*argv[])
36 {
37 if(argc!=3){
38 printf("Usage:%s [local_ip] [local_port]\n",argv[0]);
39 return 1;
40 }
41 int listen_sock = startup(argv[1],atoi(argv[2]));
42 int maxfds = 0; //max fd_set
43 fd_set rfds;//fd_set
44 int array_size = sizeof(array_fds)/sizeof(array_fds[0]);
45 array_fds[0] = listen_sock;
46
47 //init array_fds
48 int i = 1;
49 for(;i<array_size;i++){
50 array_fds[i] = -1; 51 }
52
53 while(1)
54 {
55 struct timeval timeout = {0,0};
56 FD_ZERO(&rfds); //empty
57 maxfds = -1;
58 i = 0;
59 for(;i<array_size;i++)
60 {
61 if(array_fds[i]>0){
62 FD_SET(array_fds[i],&rfds); //put array_fds[i] into rfds
63 if(array_fds[i] > maxfds){
64 maxfds = array_fds[i];
65 }
66 }
67 }
68 switch(select(maxfds+1,&rfds,NULL,NULL,NULL))
69 {
70 case 0:
71 printf("timeout...\n");
72 break;
73 case -1:
74 perror("select");
75 break;
76 default://success
77 {
78 int j = 0;
79 for(;j<array_size;++j)
80 {
81 if(array_fds[i]<0)
82 continue;
83 if(j==0&&FD_ISSET(array_fds[j],&rfds))
84 {
85 struct sockaddr_in client;
86 socklen_t len = sizeof(client);
87 int new_fd = accept(array_fds[j],(struct sockaddr*)&client,&len);
88 if(new_fd < 0){
89 perror("accept");
90 continue;
91 }
92 else{
93 printf("get a client:%s,%d\n",\
94 inet_ntoa(client.sin_addr),\
95 ntohs(client.sin_port));
96 int k = 1;
97 for(;k<array_size;k++){
98 if(array_fds[k] <0){
99 array_fds[k] = new_fd;
101 }
102 if( k == array_size){
103 //no use file
104 close(new_fd);
105 }
106 }
107 }
108 }
109 else if(j!=0&&FD_ISSET(array_fds[j],&rfds))
110 {
111 char buf[1240];
112 ssize_t s = read(array_fds[j],\
113 buf,sizeof(buf)-1);
114 if(s > 0){
115 buf[s]=0;
116 printf("client say#:%s\n",buf);
117 }
118 else if(s==0){
119 printf("client quit\n");
120 close(array_fds[j]);
121 array_fds[j]=-1;
122 }
123 else{
124 perror("read");
125 close(array_fds[j]);
126 }
127 }
128 }
129 break;
130 }
131 }
132 }
133 return 0;
134 }