zoukankan      html  css  js  c++  java
  • Linux网络编程服务器模型选择之循环服务器

         在网络程序里面,通常都是一个服务器处理多个客户机,为了出个多个客户机的请求,服务器端的程序有不同的处理方式。本节开始介绍Linux下套接字编程的服务器模型选择,主要包括循环服务器模型、并发服务器模型、IO复用服务器模型等,这也是我们常见的几种网络服务器模型。其中基本可以分为两大类,

    1. 循环服务器:循环服务器在同一时刻只能响应一个客户端的请求,是比较简单的一种模型;

    2. 并发服务器:并发服务器在同一时刻可以响应多个客户端的请求,这里面又有很多分类,接下来会逐步介绍;

    循环服务器模型

         循环服务器是指对于客户端的请求和连接,服务器逐个进行处理,处理完一个连接后再处理下一个连接,属于串行处理方式,结构比较简单。该模型的算法过程如下:

    /* UDP循环服务器模型 */ 
     
    socket(); 
     
    bind(); 
     
    while(true)
    {
       recvfrom(); 
     
       process(); 
     
       sendto(); 
    } 
    
    close();
    /* TCP循环服务器模型 */ 
     
    socket(); 
     
    bind(); 
     
    listen(); 
     
    while(true) 
    { 
     
        accept(); 
     
        while(true) 
        { 
            recv(); 
     
            process(); 
     
            send(); 
        } 
     
        close(); 
    }

    从上面的的流程可以看出,TCP循环服务器比UDP循环服务器多了一个accept的过程,这也是TCP和UDP套接字编程的主要区别。TCP服务器在accept出等待客户端的到来,因为accept函数是阻塞的,因此TCP服务器会在此等待(对accept函数的不同处理是区分各类服务器的一个重要参考依据)。相应地,UDP会在recvfrom阻塞,并等待客户端的连接。

    一个循环服务器的例子

    下面给出一个简单的循环服务器样子,模拟服务器对外提供时间服务器,等待客户端到来,并返回给客户端服务器的当前时间。

    UDP循环服务器

     1 /** UDP循环服务器--server端程序**/
     2 #include <sys/types.h>
     3 #include <sys/socket.h>
     4 #include <netinet/in.h>
     5 #include <time.h>
     6 #include <string.h>
     7 #include <stdio.h>
     8 #define BUFFLEN 1024
     9 #define SERVER_PORT 12345
    10 int main(int argc, char *argv[])
    11 {
    12     int s;    //服务器套接字文件描述符
    13     struct sockaddr_in local, to;    //本地地址
    14     time_t now;        //时间
    15     char buff[BUFFLEN];//收发数据缓冲区
    16     int n = 0;
    17     int len = sizeof(to);
    18     
    19     //建立UDP套接字
    20     s = socket(AF_INET, SOCK_DGRAM, 0);
    21     
    22     //初始化地址
    23     memset(&local, 0, sizeof(local));
    24     local.sin_family = AF_INET;//AF_INET协议族
    25     local.sin_addr.s_addr = htonl(INADDR_ANY);//任意本地地址
    26     local.sin_port = htons(SERVER_PORT);//服务器端口
    27     
    28     //将套接字文件描述符绑定到本地地址和端口
    29     int err = bind(s, (struct sockaddr*)&local, sizeof(local));
    30     
    31     //主处理过程
    32     while(1)
    33     {
    34         memset(buff, 0, BUFFLEN);
    35         n = recvfrom(s, buff, BUFFLEN,0,(struct sockaddr*)&to, &len);//接收发送方数据
    36         if(n > 0 && !strncmp(buff, "TIME", 4))//判断是否合法接收数据
    37         {
    38             printf("Get One Client Connect
    ");
    39             memset(buff, 0, BUFFLEN);
    40             now = time(NULL);
    41             sprintf(buff, "%24s
    ",ctime(&now));
    42             sendto(s, buff, strlen(buff),0, (struct sockaddr*)&to, len);//发送数据
    43         }
    44     }
    45     close(s);
    46     
    47     return 0;        
    48 }
    View Code
     1 /** UDP循环服务器--client端程序**/
     2 #include <sys/types.h>
     3 #include <sys/socket.h>
     4 #include <netinet/in.h>
     5 #include <time.h>
     6 #include <string.h>
     7 #include <stdio.h>
     8 #define BUFFLEN 1024
     9 #define SERVER_PORT 12345
    10 int main(int argc, char *argv[])
    11 {
    12     int s;    //服务器套接字文件描述符
    13     struct sockaddr_in server;    //本地地址
    14     time_t now;         
    15     char buff[BUFFLEN]; 
    16     int n = 0;     
    17     int len = 0;    //地址长度
    18     
    19     //建立UDP套接字
    20     s = socket(AF_INET, SOCK_DGRAM, 0);
    21     
    22     //初始化地址接 
    23     memset(&server, 0, sizeof(server));
    24     server.sin_family = AF_INET;//AF_INET协议族
    25     server.sin_addr.s_addr = htonl(INADDR_ANY);//任意本地地址
    26     server.sin_port = htons(SERVER_PORT);//服务器端口
    27     
    28     memset(buff, 0, BUFFLEN); 
    29     strcpy(buff, "TIME"); 
    30     //发送数据
    31     sendto(s, buff, strlen(buff), 0, (struct sockaddr*)&server, sizeof(server));
    32     memset(buff, 0, BUFFLEN);
    33     //接收数据
    34     len = sizeof(server);
    35     n = recvfrom(s, buff, BUFFLEN, 0, (struct sockaddr*)&server, &len);
    36     if(n >0)
    37         printf("TIME:%s",buff);    
    38     
    39     close(s);
    40     
    41     return 0;        
    42 }
    View Code

      

    TCP循环服务器

     1 /** TCP循环服务器--server端程序**/
     2 #include <sys/types.h>
     3 #include <sys/socket.h>
     4 #include <netinet/in.h>
     5 #include <time.h>
     6 #include <string.h>
     7 #include <stdio.h>
     8 #define BUFFLEN 1024
     9 #define SERVER_PORT 12346
    10 #define BACKLOG 5
    11 int main(int argc, char *argv[])
    12 {
    13     int s_s, s_c;    /*服务器套接字文件描述符*/
    14     struct sockaddr_in local, from;    /*本地地址*/
    15     time_t now;        
    16     char buff[BUFFLEN];
    17     int n = 0;
    18     int len = sizeof(from);
    19     
    20     /*建立TCP套接字*/
    21     s_s = socket(AF_INET, SOCK_STREAM, 0);
    22     
    23     /*初始化地址*/
    24     memset(&local, 0, sizeof(local));
    25     local.sin_family = AF_INET;/*AF_INET协议族*/
    26     local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
    27     local.sin_port = htons(SERVER_PORT);/*服务器端口*/
    28     
    29     /*将套接字文件描述符绑定到本地地址和端口*/
    30     int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));
    31     err = listen(s_s, BACKLOG);/*侦听*/
    32     
    33     /*主处理过程*/
    34     while(1)
    35     {
    36         /*接收客户端连接*/
    37         s_c = accept(s_s, (struct sockaddr*)&from, &len);
    38         memset(buff, 0, BUFFLEN);
    39         n = recv(s_c, buff, BUFFLEN,0);/*接收发送方数据*/
    40         if(n > 0 && !strncmp(buff, "TIME", 4))/*判断是否合法接收数据*/
    41         {
    42             memset(buff, 0, BUFFLEN);
    43             now = time(NULL);
    44             sprintf(buff, "%24s
    ",ctime(&now));
    45             send(s_c, buff, strlen(buff),0);/*发送数据*/
    46         }
    47         close(s_c);
    48     }
    49     close(s_s);
    50     
    51     return 0;        
    52 }
    View Code 
    /**TCP循环服务器--client端程序**/
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <string.h>
    #include <stdio.h>
    
    #define BUFFLEN 1024
    #define SERVER_PORT 12346
    int main(int argc, char *argv[])
    {
        int s;    /*服务器套接字文件描述符*/
        struct sockaddr_in server;    /*本地地址*/
        char buff[BUFFLEN];
        int n = 0;    
        
        /*建立TCP套接字*/
        s = socket(AF_INET, SOCK_STREAM, 0);
        
        /*初始化地址*/
        memset(&server, 0, sizeof(server));
        server.sin_family = AF_INET;/*AF_INET协议族*/
        server.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/
        server.sin_port = htons(SERVER_PORT);/*服务器端口*/    
        
        /*连接服务器*/
        int err = connect(s, (struct sockaddr*)&server,sizeof(server));
        memset(buff, 0, BUFFLEN);
        strcpy(buff, "TIME");
        /*发送数据*/
        send(s, buff, strlen(buff), 0);
        memset(buff, 0, BUFFLEN);
        /*接收数据*/    
        n = recv(s, buff, BUFFLEN, 0);
        if(n >0){
            printf("TIME:%s",buff);    
        }
        close(s);
        
        return 0;        
    }
    View Code

    两者返回给客户端的的输出都是一样的,比如:TIME:Sat Mar 22 15:26:25 2014

    循环服务器的介绍就到这里。接下来介绍并发服务器模型。

  • 相关阅读:
    WebService的学习
    什么是事物
    数组和链表的区别
    JDK6和JDK7中的substring()方法
    为什么存储密码字符数组比字符串更合适?
    java中Queue简介
    java中队列Queue的使用
    HashMap、Hashtable、TreeMap的区别
    笔试算法题(36):寻找一棵二叉树中最远节点的距离 & 根据二叉树的前序和后序遍历重建二叉树
    笔试算法题(35):最长递增子序列 & 判定一个字符串是否可由另一个字符串旋转得到
  • 原文地址:https://www.cnblogs.com/lizhenghn/p/3617608.html
Copyright © 2011-2022 走看看