运行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