在网络通信中,服务器通常需要处理多个客户端。由于客户端的请求会同时到来,服务器端可能会采用不同的方法来处理。总体来说,服务器端可采用两种模式来实现:循环服务器模型和并发服务器模型。
循环服务器模型是指服务器端依次处理每个客户端,直到当前客户端的所有请求处理完毕,在处理下一个客户端。这类模型的优点是简单,缺点显而易见,这样会造成其他客户端等待时间过长。
为了提高服务器的并发处理能力,引入了并发服务器模型。其基本思想是在服务器端采用多任务机制(多线程或者多进程),分别为每一个客户端创建一个任务来处理,极大的提高了服务器的并发处理能力。并发服务器模型也是本片博客要实现的。
下面是搜索到的一张TCP服务器与客户端建立连接与进行通信的过程,描述的非常形象。
实例代码
/*
server.c
*/
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char * argv[])
{
pid_t pid;
int ser_socket;
struct sockaddr_in servaddr,cliaddr;
int addr_len = sizeof(cliaddr);
int client;
char buffer[4000],renew[4000];
int datanum;
if(argc < 3)
{
printf("Usage:%s <IP> <port>\n", argv[0]); //提示输入
exit(-1);
}
if ((ser_socket = socket(AF_INET,SOCK_STREAM,0))<0)
{
perror("socket");
return -1;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
if(bind(ser_socket,(struct sockaddr *)&servaddr,sizeof(servaddr))<0)
{
perror("bind");
return -1;
}
if(listen(ser_socket, 10)<0)
{
perror("listen");
return -1;
}
//等待请求
while (1) {
printf("Listening on port :%d\n",atoi(argv[2]));
client = accept(ser_socket, (struct sockaddr*)&cliaddr, (socklen_t *)&addr_len);
if(client<0)
{
perror("accept");
continue;
}
printf("\n recv client data:\n");
printf("IP is %s\n",inet_ntoa(cliaddr.sin_addr));
printf("port is %d\n",htons(cliaddr.sin_port));
//进行对话,创建线程
if((pid = fork())==0)
{
close(ser_socket);
while(1)
{
datanum = recv(client, buffer, 4000, 0);// 收数据
if(datanum< 0)
{
perror("recv");
continue;
}
buffer[datanum] = '\0';
printf("%d:say %s\n", htons(cliaddr.sin_port), buffer);
printf("you want to say:");
scanf("%s",renew);
send(client, renew, strlen(renew), 0);
if(strcmp(renew, "quit") == 0)
{
exit(0);//销毁此线程
break;
}
}
}
}
return 0;
}
/*
client2.c
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char * argv[])
{
int client_socket;
struct sockaddr_in servaddr;
char sendbuf[400];
char recbuf[400];
int sennum,recnum;
if(argc < 3)
{
printf("Usage:%s <IP> <port>\n", argv[0]); //提示输入
exit(-1);
}
if((client_socket= socket(AF_INET, SOCK_STREAM, 0))<0)
{
perror("socket");
return -1;
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(client_socket, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("connect");
return 1;
}
printf("connect with destination host...\n");
while(1)
{
printf("Input your world:>");
scanf("%s", sendbuf);
printf("\n");
send(client_socket, sendbuf, strlen(sendbuf), 0);
recnum = recv(client_socket, recbuf, 4000, 0);
recbuf[recnum] = '\0';
printf("recv is: %s\n", recbuf);
if(strcmp(recbuf, "quit") == 0)
break;
}
close(client_socket);
return 0;
}
/*
client2.c
*/
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, const char * argv[]) {
int client_socket;
struct sockaddr_in servaddr;
char sendbuf[400];
char recbuf[400];
int sennum,recnum;
if(argc < 3)
{
printf("Usage:%s <IP> <port>\n", argv[0]); //提示输入
exit(-1);
}
if((client_socket= socket(AF_INET, SOCK_STREAM, 0))<0)
{
perror("socket");
return -1;
}
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2]));
servaddr.sin_addr.s_addr = inet_addr(argv[1]);
if(connect(client_socket, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("connect");
return 1;
}
printf("connect with destination host...\n");
while(1)
{
printf("Input your world:>");
scanf("%s", sendbuf);
printf("\n");
send(client_socket, sendbuf, strlen(sendbuf), 0);
recnum = recv(client_socket, recbuf, 4000, 0);
recbuf[recnum] = '\0';
printf("recv is: %s\n", recbuf);
if(strcmp(recbuf, "quit") == 0)
break;
}
close(client_socket);
return 0;
}