Linux应用编程—15.并发服务器模型
并发服务器模型,之前编写的基于TCP/UDP的服务器模型只支持一个客户端访问。但实际应用过程中可能同一时刻有很多的客户端进行访问。比如12360的网站、购物网站等等。对于这种需求,提出了并发服务器的模型。
这里提出常见的两种并发服务器模型,多进程式与多线程式 。前者是提前创建一定数量的进程,等待客户端与之连接,优点是与客户端的响应快速,缺点是事先不知道有多少客户端,进程创建过多造成资源浪费,进程过少,导致客户端无法正常访问。后者在有客户端连接请求后,才创建线程,在线程中处理客户端相关程序。优点是来一个客户端连接请求,节约资源;缺点是客户端连接后才创建进程处理,及时性变差。
15.1 多进程式并发服务器模型
代码在之前TCP_Server.c的基础上改写。在while(1)前调用4次fork()函数创建出16个进程,进程中执行阻塞等待客户端连接及以后的代码。
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define FAILE -1
#define SUCCESS 0
#define PORT 8800
#define SIZE 100
int main(void)
{
int ret = 0, i = 0;
int sock_fd, client_sockfd = 0;
int addr_len = sizeof(struct sockaddr);
char str[SIZE] = "Welcom to connect Server.";
struct sockaddr_in my_sockaddr, client_addr;
my_sockaddr.sin_family = AF_INET;
my_sockaddr.sin_port = htons(PORT);
my_sockaddr.sin_addr.s_addr = INADDR_ANY;
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if(sock_fd == FAILE)
perror("socket.");
ret = bind(sock_fd, (struct sockaddr *)&my_sockaddr, sizeof(struct sockaddr));
if(ret == FAILE)
perror("bind.");
ret = listen(sock_fd, 10);
if(ret == FAILE)
perror("listen.");
for(i = 0; i < 4; i++)
fork();
while(1)
{
printf("Server is waiting for client to connect:\n");
client_sockfd = accept(sock_fd, (struct sockaddr *)&client_addr, &addr_len);
printf("Client address = %s\n", inet_ntoa(client_addr.sin_addr));
send(client_sockfd, str, SIZE, 0);
printf("Disconnect the client request.\n");
close(client_sockfd);
}
close(sock_fd);
return 0;
}
运行结果:
客户端代码无改变,由于主机数量限制,还是无法现实多个客户端同时访问。但原理解释的效果以达到。
15.2 多线程并发服务器模型
代码在之前TCP_Server.c的基础上改写。当我接收到一个客户端连接请求后创建线程,在线程回调函数中执行代码。代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#define FAILE -1
#define SUCCESS 0
#define PORT 8800
#define SIZE 100
int client_sockfd = 0;
struct sockaddr_in client_addr;
char str[SIZE] = "Welcom to connect Server.";
void * thread_function(void *arg);
int main(void)
{
int ret = 0, i = 0;
int sock_fd;
int addr_len = sizeof(struct sockaddr);
struct sockaddr_in my_sockaddr;
pthread_t thread;
my_sockaddr.sin_family = AF_INET;
my_sockaddr.sin_port = htons(PORT);
my_sockaddr.sin_addr.s_addr = INADDR_ANY;
sock_fd = socket(AF_INET, SOCK_STREAM, 0);
if(sock_fd == FAILE)
perror("socket.");
ret = bind(sock_fd, (struct sockaddr *)&my_sockaddr, sizeof(struct sockaddr));
if(ret == FAILE)
perror("bind.");
ret = listen(sock_fd, 10);
if(ret == FAILE)
perror("listen.");
while(1)
{
printf("Server is waiting for client to connect:\n");
client_sockfd = accept(sock_fd, (struct sockaddr *)&client_addr, &addr_len);
pthread_create(&thread, NULL, thread_function, NULL);
}
close(sock_fd);
return 0;
}
void * thread_function(void *arg)
{
printf("Client address = %s\n", inet_ntoa(client_addr.sin_addr));
send(client_sockfd, str, SIZE, 0);
printf("Disconnect the client request.\n");
close(client_sockfd);
return NULL;
}
gcc TCP_Server.c -o SERVER -pthread,运行结果如下图2所示: