Linux网络编程客户\服务器设计范式
2017-06-25 00:34
387 查看
1、前言
网络编程分为客户端和服务端,服务器通常分为迭代服务器和并发服务器。并发服务器可以根据多进程或多线程进行细分,给每个连接创建一个独立的进程或线程,或者预先分配好多个进程或线程等待连接的请求。今天探讨三种设计范式
(1)迭代服务器
(2)并发服务器,为每个客户请求创建一个进程或线程
(3)预先分配子进程或线程,每个子进程或线程调用accept
3、测试用例:
客户端代码:
迭代服务器代码如下:
并发服务器,为每个客户请求创建一个进程测试代码如下:
预先分配子进程,每个子进程调用accept测试代码如下:
网络编程分为客户端和服务端,服务器通常分为迭代服务器和并发服务器。并发服务器可以根据多进程或多线程进行细分,给每个连接创建一个独立的进程或线程,或者预先分配好多个进程或线程等待连接的请求。今天探讨三种设计范式
(1)迭代服务器
(2)并发服务器,为每个客户请求创建一个进程或线程
(3)预先分配子进程或线程,每个子进程或线程调用accept
3、测试用例:
客户端代码:
#include <sys/wait.h> #include <string.h> #include <errno.h> #include <netdb.h> #include <stdlib.h> #define IP "127.0.0.1" #define PORT 8888 #define WORKER 4 #define MAXIN 4096 #define MAXLINE 4096 int tcp_connect(const char *host, const char *port) { if (host == NULL || port == NULL) { return -1; } int sockfd, n; struct addrinfo hints, *res, *ressave; bzero(&hints, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((n = getaddrinfo(host, port, &hints, &res)) != 0) { printf("tcp_connect error for %s,%s: %s\n", host, port, strerror(errno)); return -1; } ressave = res; do { sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) { continue; } if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) { break; } close(sockfd); } while( (res = res->ai_next) != NULL); if (res == NULL) { printf("tcp_connect error for %s,%s: %s", host, port, strerror(errno)); return -1; } freeaddrinfo(ressave); return sockfd; } int main(int argc, char **argv) { if (argc != 6) { printf("usage: client <hostname or IPaddr> <port> <#children> <#loops/child> <#bytes/request>\n"); return -1; } int i, j, fd, nchildlen, nloops, nbytes; pid_t pid; ssize_t n; char request[MAXLINE], reply[MAXIN]; nchildlen = atoi(argv[3]); nloops = atoi(argv[4]); nbytes = atoi(argv[5]); snprintf(request, sizeof(request), "%d\n", nbytes); for (i = 0; i < nchildlen; i++) { if ((pid = fork()) == 0) { for (j = 0; j < nloops; j++) { fd = tcp_connect(argv[1], argv[2]); if (fd > 0) { write(fd, request, strlen(request)); if ((n = read(fd, reply, nbytes)) != nbytes) { printf("read from server is:%s\n", reply); } close(fd); } else { break; } } printf("child %d done\n", i); exit(0); } } /*waits all child process*/ while (wait(NULL) > 0) ; if (errno != ECHILD) { fprintf(stderr, "wait error"); return -1; } return 0; }
迭代服务器代码如下:
#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 <string.h> #include <errno.h> #define IP "127.0.0.1" #define PORT 8888 #define MAXLINE 4096 int main() { int listenfd, connfd; 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); 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); char buffer[MAXLINE]; while (1) { printf("begin to accept.\n"); int connfd = accept( listenfd, ( struct sockaddr* )&client_addr, &client_addrlen ); if (connfd != -1) { printf("accept a connection success.ip :%s, port :%d\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port); } else { printf("accept a connection failed,error:%s", strerror(errno)); } int nbytes = read(connfd, buffer, MAXLINE); printf("read from client is:%s\n", buffer); write(connfd, buffer, nbytes); close(connfd); } return 0; }
并发服务器,为每个客户请求创建一个进程测试代码如下:
#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\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测试代码如下:
#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 WORKER 4 #define MAXLINE 4096 int worker(int listenfd, int i) { while (1) { printf("I am worker %d, begin to accept connection.\n", i); struct sockaddr_in client_addr; socklen_t client_addrlen = sizeof( client_addr ); int connfd = accept( listenfd, ( struct sockaddr* )&client_addr, &client_addrlen ); if (connfd != -1) { printf("worker %d accept a connection success. ip:%s, prot:%d\n", i, inet_ntoa(client_addr.sin_addr), client_addr.sin_port); } else { printf("worker %d accept a connection failed,error:%s", i, strerror(errno)); } char buffer[MAXLINE]; int nbytes = read(connfd, buffer, MAXLINE); printf("read from client is:%s\n", buffer); write(connfd, buffer, nbytes); close(connfd); } return 0; } int main() { int i = 0; struct sockaddr_in address; bzero(&address, sizeof(address)); address.sin_family = AF_INET; inet_pton( AF_INET, IP, &address.sin_addr); address.sin_port = htons(PORT); int 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); for (i = 0; i < WORKER; i++) { printf("Create worker %d\n", i+1); pid_t pid = fork(); /*child process */ if (pid == 0) { worker(listenfd, i); } if (pid < 0) { printf("fork error"); } } /*wait child process*/ while (wait(NULL) != 0) ; if (errno == ECHILD) { fprintf(stderr, "wait error:%s\n", strerror(errno)); } return 0; }
相关文章推荐
- linux 网络编程:多客户请求服务器( C/S )实例
- 【Linux的高级应用编程】网络编程中并发服务器的设计模式
- 【嵌入式Linux学习七步曲之第七篇 Linux的高级应用编程】网络编程中并发服务器的设计模式
- Linux网络编程一步一步学-自己编写一个HTTP协议的目录浏览和文件下载服务器
- Linux网络编程--9. 服务器模型
- Linux网络服务器socket编程
- Linux 网络编程一步一步学(六)-客户/服务端通信
- Linux网络编程--服务器模型
- Linux网络编程-简单的客户端和服务器通讯程序开发入门(2)
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- Linux 网络编程一步一步学(三)-循环读取服务器上的数据
- Linux网络编程:3. 服务器和客户机的信息函数
- 网络编程中设计并发服务器,使用多进程 与 多线程 ,请问有什么区别?
- Linux网络编程-服务器和客户机的信息函数(3)
- Linux 网络编程基础 客户端/服务器的简单实现
- Linux 网络编程基础(一) ---------------客户端/服务器的简单实现
- Linux网络编程一步一步学-编写一个HTTP协议的目录浏览和文件下载服务器
- 网络编程及服务器设计牛文阅读笔记
- Linux网络编程:TCP服务器(单进程多用户),使用select方法实现
- TCP服务器设计范式 - 每个客户连接对应一个线程