linux之linux 并发编程(1)

    一个好的服务器,一般都是并发服务器(同一时刻可以响应多个客户端的请求)。并发服务器设计技术一般有:多进程服务器、多线程服务器、I/O复用服务器等。

多进程并发服务器

在 Linux 环境下多进程的应用很多,其中最主要的就是网络/客户服务器。多进程服务器是当客户有请求时,服务器用一个子进程来处理客户请求。父进程继续等待其它客户的请求。这种方法的优点是当客户有请求时,服务器能及时处理客户,特别是在客户服务器交互系统中。对于一个 TCP 服务器,客户与服务器的连接可能并不马上关闭,可能会等到客户提交某些数据后再关闭,这段时间服务器端的进程会阻塞,所以这时操作系统可能调度其它客户服务进程,这比起循环服务器大大提高了服务性能。

tcp多进程并发服务器

TCP 并发服务器的思想是每一个客户机的请求并不由服务器直接处理,而是由服务器创建一个子进程来处理。
参考代码:
 
  1 #include <stdio.h>
  2  
  3 #include <stdlib.h>
  4  
  5 #include <string.h>
  6  
  7 #include <unistd.h>
  8  
  9 #include <sys/socket.h>
 10  
 11 #include <netinet/in.h>
 12  
 13 #include <arpa/inet.h>
 14  
 15 /************************************************************************
 16  
 17 函数名称: void main(int argc, char *argv[])
 18  
 19 函数功能: 主函数,用进程建立一个TCP Echo Server
 20  
 21 函数参数: 无
 22  
 23 函数返回: 无
 24  
 25 ************************************************************************/
 26  
 27 int main(int argc, char *argv[])
 28  
 29 {
 30  
 31 unsigned short port = 8080; // 本地端口
 32  
 33 //1.创建tcp套接字
 34  
 35 int sockfd = socket(AF_INET, SOCK_STREAM, 0);
 36  
 37 if(sockfd < 0)
 38  
 39 {
 40  
 41 perror("socket");
 42  
 43 exit(-1);
 44  
 45 }
 46  
 47 //配置本地网络信息
 48  
 49 struct sockaddr_in my_addr;
 50  
 51 bzero(&my_addr, sizeof(my_addr)); // 清空
 52  
 53 my_addr.sin_family = AF_INET; // IPv4
 54  
 55 my_addr.sin_port = htons(port); // 端口
 56  
 57 my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // ip
 58  
 59 //2.绑定
 60  
 61 int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));
 62  
 63 if( err_log != 0)
 64  
 65 {
 66  
 67 perror("binding");
 68  
 69 close(sockfd);
 70  
 71 exit(-1);
 72  
 73 }
 74  
 75 //3.监听,套接字变被动
 76  
 77 err_log = listen(sockfd, 10);
 78  
 79 if(err_log != 0)
 80  
 81 {
 82  
 83 perror("listen");
 84  
 85 close(sockfd);
 86  
 87 exit(-1);
 88  
 89 }
 90  
 91 while(1) //主进程 循环等待客户端的连接
 92  
 93 {
 94  
 95 char cli_ip[INET_ADDRSTRLEN] = {0};
 96  
 97 struct sockaddr_in client_addr;
 98  
 99 socklen_t cliaddr_len = sizeof(client_addr);
100  
101 // 取出客户端已完成的连接
102  
103 int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);
104  
105 if(connfd < 0)
106  
107 {
108  
109 perror("accept");
110  
111 close(sockfd);
112  
113 exit(-1);
114  
115 }
116  
117 pid_t pid = fork();
118  
119 if(pid < 0){
120  
121 perror("fork");
122  
123 _exit(-1);
124  
125 }else if(0 == pid){ //子进程 接收客户端的信息,并发还给客户端
126  
127 /*关闭不需要的套接字可节省系统资源,
128  
129 同时可避免父子进程共享这些套接字
130  
131 可能带来的不可预计的后果
132  
133 */
134  
135 close(sockfd); // 关闭监听套接字,这个套接字是从父进程继承过来
136  
137 char recv_buf[1024] = {0};
138  
139 int recv_len = 0;
140  
141 // 打印客户端的 ip 和端口
142  
143 memset(cli_ip, 0, sizeof(cli_ip)); // 清空
144  
145 inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
146  
147 printf("----------------------------------------------\n");
148  
149 printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));
150  
151 // 接收数据
152  
153 while( (recv_len = recv(connfd, recv_buf, sizeof(recv_buf), 0)) > 0 )
154  
155 {
156  
157 printf("recv_buf: %s\n", recv_buf); // 打印数据
158  
159 send(connfd, recv_buf, recv_len, 0); // 给客户端回数据
160  
161 }
162  
163 printf("client_port %d closed!\n", ntohs(client_addr.sin_port));
164  
165 close(connfd); //关闭已连接套接字
166  
167 exit(0);
168  
169 }
170  
171 else if(pid > 0){ // 父进程
172  
173 close(connfd); //关闭已连接套接字
174  
175 }
176  
177 }
178 close(sockfd);
179  
180 return 0;
181  
182 }
183  
184  

 

 
posted @ 2020-03-27 17:42  Sunny_Boy_H  阅读(494)  评论(0编辑  收藏  举报