第26课-网络并发服务器设计
26.1 问题描述
在我们第24节课操作的内容中。是有一个服务器和一个客户端的条件。但是在生活中,我们会遇到多个客户端的情况。我们先在linux系统上做一下模拟操作,在一个终端运行./tcp_server,在另外两个终端分别运行./tcp_client程序。我们会发现客户端对第一个运行的程序响应后就不会对另一个响应,直到第一个运行结束,然后才会运行第二个。这种情况也叫循环服务器。这样的服务器处理的效率是非常低的。
26.2 解决办法
为了解决上面的问题,我们引入并发服务器,并发也就是能够同时处理的意思。可以采用的方法很多(多进程,多线程等),今天我们采用多进程的方法。
编程实现并发服务器。我们先看一下,以前我们编的程序的运行步骤:(1)创建套接字(2)绑定套接字(3)循环:建立连接,数据处理(4)结束。问题就出现在第三步上,当我们进行数据处理的时候,若没有处理完数据就会一直等待,然后才会去建立新的连接。为了解决这一个问题,我们可以建立子进程,让子进程去处理数据,父进程就可以一直处于建立连接的过程。每建立一个连接,就把它交给一个子进程。这样就提高了效率。
tcp_server_fork.c
#include<sys/socket.h>
#include<stdio.h>
#include<string.h> //字符串头文件
#include<netinet/in.h> //地址的头文件
#define portnum 3333
int main()
{
int sockfd;
int new_fd;
char buffer[128];//定义存储数据的字节
int nbyte;//接收到的字符串的长度
int sin_size;
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
int pid;
//1.创建套接字
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("creat socket error! ");
exit(1);
}
//2.1 设置要绑定的地址
bzero(&server_addr, sizeof(struct sockaddr_in));//清零
server_addr.sin_family = AF_INET; //网络协议
server_addr.sin_port = htons(portnum); //端口,超过两个字节就要转换
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//表示任意地址,超过两个字节就要转换
//2.2 绑定地址
bind(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr));//表示指针的强制转换
//3.监听端口
listen(sockfd, 5);
while(1)
{
//4.等待连接
sin_size = sizeof(struct sockaddr);
new_fd = accept(sockfd, (struct sockaddr *)(&client_addr), &sin_size);
printf("server get connection from %s ", inet_ntoa(client_addr.sin_addr));//取客户机的ip地址,并且将整型地址转换成字符串地址
//创建子进程,由子进程来处理数据
if(pid=fork() == 0) //创建子进程,如果pid等于0就是子进程,不等于0是父进程
{
//5.接收数据
nbyte = recv(new_fd,buffer,128,0);
buffer[nbyte] = ' ';//字符串的结束符
printf("server received: %s ",buffer);
close(new_fd);
close(sockfd);
exit(0);
}
else if(pid<0)
printf("fork error! ");
//6.结束连接
close(new_fd);
}
close(sockfd);
return 0;
}
tcp_client.c还用24课的程序。
运行结果:我们可以在三个端口中分别启用tcp_server_fork,tcp_client,tcp_client。我们会看到tcp_server_fork程序可以同时的去处理两个客户机的程序。