首页 > 代码库 > 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网络编程客户\服务器设计范式
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。