首页 > 代码库 > Linux网络编程客户\服务器设计范式

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 410 #define MAXIN  409611 #define MAXLINE  409612 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\n", 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>\n");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\n", 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\n", reply);70                     }71                     close(fd);72                 } else {73                     break;74                 }75             }76             printf("child %d done\n", 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  888813 #define MAXLINE   409614 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.\n");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\n", 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\n", 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 4096int 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\n",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.\n", count);            close(listenfd);            char buffer[MAXLINE];            int nbytes = read(connfd, buffer, MAXLINE);            printf("read from client is:%s\n", 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  888815 #define WORKER 416 #define MAXLINE   409617 18 int worker(int listenfd, int i)19 {20     while (1) {21         printf("I am worker %d, begin to accept connection.\n", 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\n", 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\n", 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\n", 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\n", strerror(errno));70     }71     return 0;72 }

 

Linux网络编程客户\服务器设计范式