1、简介

前面的服务器模型主要集中在并发服务器上,并发服务器有个比较大的缺陷,它需要建立多个并行的处理单元。当客户端增加时,随着处理单元的增加,系统的负载会逐渐转移到并行单元的现场切换上。因此有一个比较新型的IO复用循环服务器。该模型在系统开始时,建立多个不同工作类型的处理单元,当客户端的请求到来时,将客户端的连接放到一个状态池中,对所有客户端的连接状态在一个处理单元中进行轮询处理。

2、tcp模型
 

 

 

3、服务器源代码(concurrency-server5.c):

 

 
  
  1. #include <stdio.h> 
  2.  
  3. #include <stdlib.h> 
  4.  
  5. #include <string.h> 
  6.  
  7. #include <errno.h> 
  8.  
  9. #include <sys/socket.h> 
  10.  
  11. #include <arpa/inet.h> 
  12.  
  13. #include <netinet/in.h> 
  14.  
  15. #include <sys/types.h> 
  16.  
  17. #include <unistd.h> 
  18.  
  19. #include <time.h> 
  20.  
  21. #include <pthread.h> 
  22.  
  23.  
  24.  
  25. #define BUFLEN 1024  
  26.  
  27. #define THREADNUM 2  
  28.  
  29. #define CLIENTNUM 1024  
  30.  
  31.  
  32.  
  33. int connect_host[CLIENTNUM];  
  34.  
  35. int connect_num = 0;  
  36.  
  37. /*******************并发服务器模型之五:IO复用循环服务器**********************/  
  38.  
  39.  
  40.  
  41. static void *handle_request(void *argv){  
  42.  
  43.     char buf[BUFLEN];  
  44.  
  45.     int len;  
  46.  
  47.     time_t now;  
  48.  
  49.     int maxfd = -1;  
  50.  
  51.     fd_set rfds;  
  52.  
  53.     struct timeval tv;  
  54.  
  55.     tv.tv_sec = 1;  
  56.  
  57.     tv.tv_usec = 0;  
  58.  
  59.     int i =0;  
  60.  
  61.     int err = -1;  
  62.  
  63.  
  64.  
  65.     while(1){  
  66.  
  67.         FD_ZERO(&rfds);  
  68.  
  69.         for(i = 0; i < CLIENTNUM; i++){  
  70.  
  71.             if(connect_host[i] != -1){  
  72.  
  73.                 FD_SET(connect_host[i],&rfds);  
  74.  
  75.                 if(maxfd < connect_host[i])  
  76.  
  77.                     maxfd = connect_host[i];  
  78.  
  79.             }      
  80.  
  81.         }  
  82.  
  83.         err = select(maxfd+1, &rfds, NULL, NULL, &tv);  
  84.  
  85.         switch(err){  
  86.  
  87.             case 0: break;  
  88.  
  89.             case -1: break;  
  90.  
  91.             default:  
  92.  
  93.                 if (connect_num < 0)  
  94.  
  95.                     break;  
  96.  
  97.                 for(i = 0; i < CLIENTNUM; i++){  
  98.  
  99.                     if(connect_host[i] != -1){  
  100.  
  101.                         if(FD_ISSET(connect_host[i],&rfds)){  
  102.  
  103.                             /******处理客户端请求*******/  
  104.  
  105.                             bzero(buf,BUFLEN);  
  106.  
  107.                             len = recv(connect_host[i],buf,BUFLEN,0);  
  108.  
  109.                             if(len >0 && !strncmp(buf,"TIME",4)){  
  110.  
  111.                                 bzero(buf,BUFLEN);  
  112.  
  113.                                 /*获取系统当前时间*/  
  114.  
  115.                                 now = time(NULL);  
  116.  
  117.                                 /*ctime将系统时间转换为字符串,sprintf使转化后的字符串保存在buf*/  
  118.  
  119.                                 sprintf(buf,"%24s\r\n",ctime(&now));  
  120.  
  121.                                 //******发送系统时间*******/  
  122.  
  123.                                 send(connect_host[i],buf,strlen(buf),0);  
  124.  
  125.                             }  
  126.  
  127.                             /*关闭通讯的套接字*/  
  128.  
  129.                             close(connect_host[i]);  
  130.  
  131.                             /*更新文件描述符在数组中的值*/  
  132.  
  133.                             connect_host[i] = -1;  
  134.  
  135.                             connect_num--;      
  136.  
  137.                         }  
  138.  
  139.                     }              
  140.  
  141.                 }  
  142.  
  143.                 break;  
  144.  
  145.         }  
  146.  
  147.     }  
  148.  
  149.     return NULL;  
  150.  
  151. }  
  152.  
  153.  
  154.  
  155. static void *handle_connect(void *arg){  
  156.  
  157.     int sockfd = *((int *)arg);  
  158.  
  159.     int newfd;  
  160.  
  161.     struct sockaddr_in c_addr;  
  162.  
  163.     socklen_t len;  
  164.  
  165.     int i;  
  166.  
  167.  
  168.  
  169.     while(1){  
  170.  
  171.         len = sizeof(struct sockaddr);  
  172.  
  173.         if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) >0){  
  174.  
  175.             printf("\n*****************通信开始***************\n");  
  176.  
  177.             printf("正在与您通信的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));  
  178.  
  179.             for(i = 0; i < CLIENTNUM; i++){  
  180.  
  181.                 if(connect_host[i] == -1){  
  182.  
  183.                     connect_host[i] = newfd;  
  184.  
  185.                     /*客户端计数器*/  
  186.  
  187.                     connect_num++;  
  188.  
  189.                     /*继续等待新的客户端*/  
  190.  
  191.                     break;              
  192.  
  193.                 }  
  194.  
  195.             }  
  196.  
  197.         }  
  198.  
  199.     }  
  200.  
  201.     return NULL;  
  202.  
  203. }  
  204.  
  205.  
  206.  
  207. int main(int argc, char **argv)  
  208.  
  209. {  
  210.  
  211.     int sockfd;  
  212.  
  213.     struct sockaddr_in s_addr;  
  214.  
  215.     unsigned int port, listnum;  
  216.  
  217.     pthread_t thread_s[2];  
  218.  
  219.       
  220.  
  221.     /**/      
  222.  
  223.     memset(connect_host,-1,CLIENTNUM);  
  224.  
  225.     /*建立socket*/  
  226.  
  227.     if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){  
  228.  
  229.         perror("socket");  
  230.  
  231.         exit(errno);  
  232.  
  233.     }else  
  234.  
  235.         printf("socket create success!\n");  
  236.  
  237.     /*设置服务器端口*/      
  238.  
  239.     if(argv[2])  
  240.  
  241.         port = atoi(argv[2]);  
  242.  
  243.     else  
  244.  
  245.         port = 4567;  
  246.  
  247.     /*设置侦听队列长度*/  
  248.  
  249.     if(argv[3])  
  250.  
  251.         listnum = atoi(argv[3]);  
  252.  
  253.     else  
  254.  
  255.         listnum = 3;  
  256.  
  257.     /*设置服务器ip*/  
  258.  
  259.     bzero(&s_addr, sizeof(s_addr));  
  260.  
  261.     s_addr.sin_family = AF_INET;  
  262.  
  263.     s_addr.sin_port = htons(port);  
  264.  
  265.     if(argv[1])  
  266.  
  267.         s_addr.sin_addr.s_addr = inet_addr(argv[1]);  
  268.  
  269.     else  
  270.  
  271.         s_addr.sin_addr.s_addr = INADDR_ANY;  
  272.  
  273.     /*把地址和端口帮定到套接字上*/  
  274.  
  275.     if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){  
  276.  
  277.         perror("bind");  
  278.  
  279.         exit(errno);  
  280.  
  281.     }else  
  282.  
  283.         printf("bind success!\n");  
  284.  
  285.     /*侦听本地端口*/  
  286.  
  287.     if(listen(sockfd,listnum) == -1){  
  288.  
  289.         perror("listen");  
  290.  
  291.         exit(errno);      
  292.  
  293.     }else  
  294.  
  295.         printf("the server is listening!\n");  
  296.  
  297.     /*创建线程处理客户端的连接*/  
  298.  
  299.     pthread_create(&thread_s[0],NULL,handle_connect,(void *)&sockfd);  
  300.  
  301.     /*创建线程处理客户端的请求*/  
  302.  
  303.     pthread_create(&thread_s[1],NULL,handle_request, NULL);  
  304.  
  305.     /*等待线程结束*/  
  306.  
  307.     int i;  
  308.  
  309.     for(i = 0; i < THREADNUM; i++){  
  310.  
  311.         pthread_join(thread_s[i],NULL);  
  312.  
  313.     }  
  314.  
  315.     /*关闭服务器的套接字*/  
  316.  
  317.     close(sockfd);  
  318.  
  319.     return 0;  
  320.  
  321. }  

4、客户端源代码(concurrency-client.c)与之前的一样。

5、编译源代码:

new@new-desktop:~/linux/c$ gcc -Wall –lpthread concurrency-server5.c -o server

new@new-desktop:~/linux/c$ gcc -Wall concurrency-client.c -o client

6、运行,试试吧