【网络编程】学习笔记--05 I/O多路复用之select

运行select的server端:

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #include<unistd.h>
 5 #include<errno.h>
 6 #include<pthread.h>
 7 #include<ctype.h>
 8 #include<sys/socket.h>
 9 #include<arpa/inet.h>
10 
11 #define SERV_PORT 9527
12 
13 void sys_err(const char *str)
14 {
15     perror(str);
16     exit(1);
17 }
18 
19 int main(int argc,char *argv[])
20 {
21     int listenfd = 0,connfd = 0;
22     char buf[BUFSIZ];
23 
24     struct sockaddr_in serv_addr,clie_addr;
25     socklen_t clie_addr_len;
26     
27     listenfd = socket(AF_INET,SOCK_STREAM,0);
28 
29     int opt = 1;
30     setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
31 
32     memset(&serv_addr,0,sizeof(serv_addr));
33     serv_addr.sin_family = AF_INET;
34     serv_addr.sin_port = htons(SERV_PORT);
35     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
36     bind(listenfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
37     listen(listenfd,128);
38 
39     fd_set rset,allset;                 //定义读集合rset,备份集合allset
40     int ret,maxfd = 0,n,i,j;
41     maxfd = listenfd;                   //最大文件描述符
42 
43     FD_ZERO(&allset);                   //清空监听集合
44     FD_SET(listenfd,&allset);           //将待监听fd添加到监听集合中
45 
46     while(1){
47         rset = allset;                  //备份
48         ret = select(maxfd+1, &rset, NULL, NULL,NULL);  //使用select监听
49         
50         if(FD_ISSET(listenfd,&rset)){               //listenfd满足监听读事件
51             clie_addr_len = sizeof(clie_addr);
52             connfd = accept(listenfd, (struct sockaddr *)&clie_addr, &clie_addr_len); //与客户端建立连接,不会阻塞
53 
54             FD_SET(connfd, &allset);        //将新产生的fd添加到监听集合中,监听数据读事件
55             if(maxfd < connfd)              //修改maxfd
56                 maxfd = connfd;
57 
58             if(ret == 1)                    //说明select返回值只有1个,并且是listenfd,后续无需执行
59                 continue;
60         }
61         for(i = listenfd+1; i<=maxfd; i++){     //处理满足读事件的fd
62             if(FD_ISSET(i,&rset)){              //找到满足读事件的fd
63                 n = read(i,buf,sizeof(buf));
64                 if(n == 0){                     //检测到客户端已经关闭连接
65                     close(i);
66                     FD_CLR(i,&allset);          //将关闭的fd移除出监听集合
67                 }
68 
69                 for(j = 0; j < n;j++)
70                     buf[j] = toupper(buf[j]);
71 
72                 write(i,buf,n);
73                 write(STDOUT_FILENO,buf,n);
74             }
75         }
76     }
77     close(listenfd);
78     return 0;
79 }

 

select的架构如下:

 

 

缺陷:内部判断只能轮询(比如只有3,5,1024,这样的话你需要遍历到死),要优化的话需要加数组。暨监听上限受文件描述符限制,最大1024

   select最多只能支持1024个客户端,如果要5000个客户端就吃不消,所以需要加进程。

优点:跨平台:win,linux等。而epoll只支持linux

 

posted @ 2021-11-12 16:38  Anonytt  阅读(36)  评论(0编辑  收藏  举报