zoukankan      html  css  js  c++  java
  • Linux网络编程客户服务器设计范式

    1、前言

      网络编程分为客户端和服务端,服务器通常分为迭代服务器和并发服务器。并发服务器可以根据多进程或多线程进行细分,给每个连接创建一个独立的进程或线程,或者预先分配好多个进程或线程等待连接的请求。今天探讨三种设计范式

    (1)迭代服务器

    (2)并发服务器,为每个客户请求创建一个进程或线程

    (3)预先分配子进程或线程,每个子进程或线程调用accept

    3、测试用例:

    客户端代码:

     1 #include <sys/wait.h>
     2 #include <string.h>
     3 #include <errno.h>
     4 #include <netdb.h>
     5 #include <stdlib.h>
     6 
     7 #define IP   "127.0.0.1"
     8 #define PORT  8888
     9 #define WORKER 4
    10 #define MAXIN  4096
    11 #define MAXLINE  4096
    12 
    13 int tcp_connect(const char *host, const char *port)
    14 {
    15     if (host == NULL || port == NULL) {
    16         return -1;
    17     }
    18     int sockfd, n;
    19     struct addrinfo hints, *res, *ressave;
    20     bzero(&hints, sizeof(struct addrinfo));
    21     hints.ai_family = AF_UNSPEC;
    22     hints.ai_socktype = SOCK_STREAM;
    23     if ((n = getaddrinfo(host, port, &hints, &res)) != 0) {
    24         printf("tcp_connect error for %s,%s: %s
    ", host, port,  strerror(errno));
    25         return -1;
    26     }
    27     ressave = res;
    28     do {
    29         sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    30         if (sockfd < 0) {
    31             continue;
    32         }
    33         if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
    34             break;
    35         }
    36         close(sockfd);
    37     } while( (res = res->ai_next) != NULL);
    38     if (res == NULL) {
    39         printf("tcp_connect error for %s,%s: %s", host, port,  strerror(errno));
    40         return -1;
    41     }
    42     freeaddrinfo(ressave);
    43     return sockfd;
    44 }
    45 
    46 int main(int argc, char **argv)
    47 {
    48     if (argc != 6) {
    49         printf("usage: client <hostname or IPaddr> <port> <#children> <#loops/child> <#bytes/request>
    ");
    50         return -1;
    51     }
    52 
    53     int i, j, fd, nchildlen, nloops, nbytes;
    54     pid_t pid;
    55     ssize_t n;
    56     char request[MAXLINE], reply[MAXIN];
    57     nchildlen = atoi(argv[3]);
    58     nloops = atoi(argv[4]);
    59     nbytes = atoi(argv[5]);
    60     snprintf(request, sizeof(request), "%d
    ", nbytes);
    61     for (i = 0; i < nchildlen; i++) {
    62         if ((pid = fork()) == 0) {
    63             for (j = 0; j < nloops; j++) {
    64                 fd = tcp_connect(argv[1], argv[2]);
    65                 if (fd > 0) {
    66                     write(fd, request, strlen(request));
    67 
    68                     if ((n = read(fd, reply, nbytes)) != nbytes) {
    69                         printf("read from server is:%s
    ", reply);
    70                     }
    71                     close(fd);
    72                 } else {
    73                     break;
    74                 }
    75             }
    76             printf("child %d done
    ", i);
    77             exit(0);
    78         }
    79     }
    80     /*waits all child process*/
    81     while (wait(NULL) > 0)
    82         ;
    83     if (errno != ECHILD) {
    84         fprintf(stderr, "wait error");
    85         return -1;
    86     }
    87     return 0;
    88 }

    迭代服务器代码如下:

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <sys/types.h>  
     4 #include <sys/socket.h>  
     5 #include <netinet/in.h>  
     6 #include <arpa/inet.h>  
     7 #include <assert.h>  
     8 #include <string.h>
     9 #include <errno.h>
    10 
    11 #define IP   "127.0.0.1"
    12 #define PORT  8888
    13 #define MAXLINE   4096
    14 
    15 int main()
    16 {
    17     int listenfd, connfd;
    18     struct sockaddr_in address, client_addr;  
    19     socklen_t client_addrlen = sizeof(client_addr);  
    20     bzero(&address, sizeof(address));  
    21     address.sin_family = AF_INET;  
    22     inet_pton( AF_INET, IP, &address.sin_addr);  
    23     address.sin_port = htons(PORT);  
    24     listenfd = socket(PF_INET, SOCK_STREAM, 0);  
    25     assert(listenfd >= 0);  
    26     int ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));  
    27     assert(ret != -1);  
    28     ret = listen(listenfd, 5);  
    29     assert(ret != -1);  
    30 
    31     char buffer[MAXLINE];
    32     while (1) {
    33         printf("begin to accept.
    ");
    34         int connfd = accept( listenfd, ( struct sockaddr* )&client_addr, &client_addrlen );  
    35         if (connfd != -1) {
    36             printf("accept a connection success.ip :%s, port :%d
    ", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
    37         } else {
    38             printf("accept a connection failed,error:%s", strerror(errno));
    39         }
    40 
    41         int nbytes = read(connfd, buffer, MAXLINE);
    42         printf("read from client is:%s
    ", buffer);
    43         write(connfd, buffer, nbytes);
    44 
    45         close(connfd);
    46     }
    47     return 0;
    48 }

    并发服务器,为每个客户请求创建一个进程测试代码如下:

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>  
    #include <sys/socket.h>  
    #include <netinet/in.h>  
    #include <arpa/inet.h>  
    #include <assert.h>  
    #include <sys/wait.h>
    #include <string.h>
    #include <errno.h>
    #include <stdlib.h>
    
    #define IP   "127.0.0.1"
    #define PORT  8888
    #define MAXLINE 4096
    
    int main()
    {
        int count = 0;
        struct sockaddr_in address, client_addr;  
        socklen_t client_addrlen = sizeof( client_addr );  
        bzero(&address, sizeof(address));  
        address.sin_family = AF_INET;  
        inet_pton( AF_INET, IP, &address.sin_addr);  
        address.sin_port = htons(PORT);  
        int listenfd,connfd;
        listenfd = socket(PF_INET, SOCK_STREAM, 0);  
        assert(listenfd >= 0);  
        int ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));  
        assert(ret != -1);  
        ret = listen(listenfd, 5);  
        assert(ret != -1);  
        while(1) {
            connfd = accept( listenfd, ( struct sockaddr* )&client_addr, &client_addrlen );  
            if (connfd == -1) {
                printf("accept a connection failed,error:%s", strerror(errno));
                break;
            } 
            printf("accept a connection success.ip: %s,prot: %d
    ",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);
            pid_t pid = fork();
            count = count + 1;
            /*child  process */
            if (pid == 0) {
                printf("Create process %d handle a new connetcion.
    ", count);
                close(listenfd);
                char buffer[MAXLINE];
                int nbytes = read(connfd, buffer, MAXLINE);
                printf("read from client is:%s
    ", buffer);
                write(connfd, buffer, nbytes);
                exit(0);
            }
            if (pid < 0) {
                printf("fork error");
            }
            close(connfd);
        }
        return 0;
    }

    预先分配子进程,每个子进程调用accept测试代码如下:

     1 #include <stdio.h>
     2 #include <unistd.h>
     3 #include <sys/types.h>  
     4 #include <sys/socket.h>  
     5 #include <netinet/in.h>  
     6 #include <arpa/inet.h>  
     7 #include <assert.h>  
     8 #include <sys/wait.h>
     9 #include <string.h>
    10 #include <errno.h>
    11 #include <stdlib.h>
    12 
    13 #define IP   "127.0.0.1"
    14 #define PORT  8888
    15 #define WORKER 4
    16 #define MAXLINE   4096
    17 
    18 int worker(int listenfd, int i)
    19 {
    20     while (1) {
    21         printf("I am worker %d, begin to accept connection.
    ", i);
    22         struct sockaddr_in client_addr;  
    23         socklen_t client_addrlen = sizeof( client_addr );  
    24         int connfd = accept( listenfd, ( struct sockaddr* )&client_addr, &client_addrlen );  
    25         if (connfd != -1) {
    26             printf("worker %d accept a connection success. ip:%s, prot:%d
    ", i, inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
    27         } else {
    28             printf("worker %d accept a connection failed,error:%s", i, strerror(errno));
    29         }
    30         char buffer[MAXLINE];
    31         int nbytes = read(connfd, buffer, MAXLINE);
    32         printf("read from client is:%s
    ", buffer);
    33         write(connfd, buffer, nbytes);
    34         close(connfd);
    35     }
    36     return 0;
    37 }
    38 
    39 int main()
    40 {
    41     int i = 0;
    42     struct sockaddr_in address;  
    43     bzero(&address, sizeof(address));  
    44     address.sin_family = AF_INET;  
    45     inet_pton( AF_INET, IP, &address.sin_addr);  
    46     address.sin_port = htons(PORT);  
    47     int listenfd = socket(PF_INET, SOCK_STREAM, 0);  
    48     assert(listenfd >= 0);  
    49     int ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));  
    50     assert(ret != -1);  
    51     ret = listen(listenfd, 5);  
    52     assert(ret != -1);  
    53 
    54     for (i = 0; i < WORKER; i++) {
    55         printf("Create worker %d
    ", i+1);
    56         pid_t pid = fork();
    57         /*child  process */
    58         if (pid == 0) {
    59             worker(listenfd, i);
    60         }
    61         if (pid < 0) {
    62             printf("fork error");
    63         }
    64     }
    65     /*wait child process*/
    66     while (wait(NULL) != 0)
    67         ;
    68     if (errno == ECHILD) {
    69         fprintf(stderr, "wait error:%s
    ", strerror(errno));
    70     }
    71     return 0;
    72 }
  • 相关阅读:
    JavaScript 为字符串添加样式 【每日一段代码80】
    JavaScript replace()方法 【每日一段代码83】
    JavaScript for in 遍历数组 【每日一段代码89】
    JavaScript 创建用于对象的模板【每日一段代码78】
    html5 css3 新元素简单页面布局
    JavaScript Array() 数组 【每日一段代码88】
    JavaScript toUTCString() 方法 【每日一段代码86】
    位运算
    POJ 3259 Wormholes
    POJ 3169 Layout
  • 原文地址:https://www.cnblogs.com/Anker/p/7075141.html
Copyright © 2011-2022 走看看