Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2691864
  • 博文数量: 505
  • 博客积分: 1552
  • 博客等级: 上尉
  • 技术积分: 2514
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-23 18:24
文章分类

全部博文(505)

文章存档

2019年(12)

2018年(15)

2017年(1)

2016年(17)

2015年(14)

2014年(93)

2013年(233)

2012年(108)

2011年(1)

2009年(11)

分类: LINUX

2014-07-20 21:46:50

1、简介

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

2、tcp模型

image

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

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <errno.h>
  5. #include <sys/socket.h>
  6. #include <arpa/inet.h>
  7. #include <netinet/in.h>
  8. #include <sys/types.h>
  9. #include <unistd.h>
  10. #include <time.h>
  11. #include <pthread.h>

  12. #define BUFLEN 1024
  13. #define THREADNUM 2
  14. #define CLIENTNUM 1024

  15. int connect_host[CLIENTNUM];
  16. int connect_num = 0;
  17. /*******************并发服务器模型之五:IO复用循环服务器**********************/

  18. static void *handle_request(void *argv){
  19.     char buf[BUFLEN];
  20.     int len;
  21.     time_t now;
  22.     int maxfd = -1;
  23.     fd_set rfds;
  24.     struct timeval tv;
  25.     tv.tv_sec = 1;
  26.     tv.tv_usec = 0;
  27.     int i =0;
  28.     int err = -1;

  29.     while(1){
  30.         FD_ZERO(&rfds);
  31.         for(i = 0; i < CLIENTNUM; i++){
  32.             if(connect_host[i] != -1){
  33.                 FD_SET(connect_host[i],&rfds);
  34.                 if(maxfd < connect_host[i])
  35.                     maxfd = connect_host[i];
  36.             }    
  37.         }
  38.         err = select(maxfd+1, &rfds, NULL, NULL, &tv);
  39.         switch(err){
  40.             case 0: break;
  41.             case -1: break;
  42.             default:
  43.                 if (connect_num < 0)
  44.                     break;
  45.                 for(i = 0; i < CLIENTNUM; i++){
  46.                     if(connect_host[i] != -1){
  47.                         if(FD_ISSET(connect_host[i],&rfds)){
  48.                             /******处理客户端请求*******/
  49.                             bzero(buf,BUFLEN);
  50.                             len = recv(connect_host[i],buf,BUFLEN,0);
  51.                             if(len >0 && !strncmp(buf,"TIME",4)){
  52.                                 bzero(buf,BUFLEN);
  53.                                 /*获取系统当前时间*/
  54.                                 now = time(NULL);
  55.                                 /*ctime将系统时间转换为字符串,sprintf使转化后的字符串保存在buf*/
  56.                                 sprintf(buf,"%24s\r\n",ctime(&now));
  57.                                 //******发送系统时间*******/
  58.                                 send(connect_host[i],buf,strlen(buf),0);
  59.                             }
  60.                             /*关闭通讯的套接字*/
  61.                             close(connect_host[i]);
  62.                             /*更新文件描述符在数组中的值*/
  63.                             connect_host[i] = -1;
  64.                             connect_num--;    
  65.                         }
  66.                     }            
  67.                 }
  68.                 break;
  69.         }
  70.     }
  71.     return NULL;
  72. }

  73. static void *handle_connect(void *arg){
  74.     int sockfd = *((int *)arg);
  75.     int newfd;
  76.     struct sockaddr_in c_addr;
  77.     socklen_t len;
  78.     int i;

  79.     while(1){
  80.         len = sizeof(struct sockaddr);
  81.         if((newfd = accept(sockfd,(struct sockaddr*) &c_addr, &len)) >0){
  82.             printf("\n*****************通信开始***************\n");
  83.             printf("正在与您通信的客户端是:%s: %d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));
  84.             for(i = 0; i < CLIENTNUM; i++){
  85.                 if(connect_host[i] == -1){
  86.                     connect_host[i] = newfd;
  87.                     /*客户端计数器*/
  88.                     connect_num++;
  89.                     /*继续等待新的客户端*/
  90.                     break;            
  91.                 }
  92.             }
  93.         }
  94.     }
  95.     return NULL;
  96. }

  97. int main(int argc, char **argv)
  98. {
  99.     int sockfd;
  100.     struct sockaddr_in s_addr;
  101.     unsigned int port, listnum;
  102.     pthread_t thread_s[2];
  103.     
  104.     /**/    
  105.     memset(connect_host,-1,CLIENTNUM);
  106.     /*建立socket*/
  107.     if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
  108.         perror("socket");
  109.         exit(errno);
  110.     }else
  111.         printf("socket create success!\n");
  112.     /*设置服务器端口*/    
  113.     if(argv[2])
  114.         port = atoi(argv[2]);
  115.     else
  116.         port = 4567;
  117.     /*设置侦听队列长度*/
  118.     if(argv[3])
  119.         listnum = atoi(argv[3]);
  120.     else
  121.         listnum = 3;
  122.     /*设置服务器ip*/
  123.     bzero(&s_addr, sizeof(s_addr));
  124.     s_addr.sin_family = AF_INET;
  125.     s_addr.sin_port = htons(port);
  126.     if(argv[1])
  127.         s_addr.sin_addr.s_addr = inet_addr(argv[1]);
  128.     else
  129.         s_addr.sin_addr.s_addr = INADDR_ANY;
  130.     /*把地址和端口帮定到套接字上*/
  131.     if((bind(sockfd, (struct sockaddr*) &s_addr,sizeof(struct sockaddr))) == -1){
  132.         perror("bind");
  133.         exit(errno);
  134.     }else
  135.         printf("bind success!\n");
  136.     /*侦听本地端口*/
  137.     if(listen(sockfd,listnum) == -1){
  138.         perror("listen");
  139.         exit(errno);    
  140.     }else
  141.         printf("the server is listening!\n");
  142.     /*创建线程处理客户端的连接*/
  143.     pthread_create(&thread_s[0],NULL,handle_connect,(void *)&sockfd);
  144.     /*创建线程处理客户端的请求*/
  145.     pthread_create(&thread_s[1],NULL,handle_request, NULL);
  146.     /*等待线程结束*/
  147.     int i;
  148.     for(i = 0; i < THREADNUM; i++){
  149.         pthread_join(thread_s[i],NULL);
  150.     }
  151.     /*关闭服务器的套接字*/
  152.     close(sockfd);
  153.     return 0;
  154. }

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、运行,试试吧

阅读(930) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~