在网络程序里面,通常都是一个服务器处理多个客户机,为了出个多个客户机的请求,服务器端的程序有不同的处理方式。本节开始介绍Linux下套接字编程的服务器模型选择,主要包括循环服务器模型、并发服务器模型、IO复用服务器模型等,这也是我们常见的几种网络服务器模型。其中基本可以分为两大类,
1. 循环服务器:循环服务器在同一时刻只能响应一个客户端的请求,是比较简单的一种模型;
2. 并发服务器:并发服务器在同一时刻可以响应多个客户端的请求,这里面又有很多分类,接下来会逐步介绍;
循环服务器模型
循环服务器是指对于客户端的请求和连接,服务器逐个进行处理,处理完一个连接后再处理下一个连接,属于串行处理方式,结构比较简单。该模型的算法过程如下:
/* UDP循环服务器模型 */ socket(); bind(); while(true) {
recvfrom();
process();
sendto();
}
close();
/* TCP循环服务器模型 */ socket(); bind(); listen(); while(true) { accept(); while(true) { recv(); process(); send(); } close(); }
从上面的的流程可以看出,TCP循环服务器比UDP循环服务器多了一个accept的过程,这也是TCP和UDP套接字编程的主要区别。TCP服务器在accept出等待客户端的到来,因为accept函数是阻塞的,因此TCP服务器会在此等待(对accept函数的不同处理是区分各类服务器的一个重要参考依据)。相应地,UDP会在recvfrom阻塞,并等待客户端的连接。
一个循环服务器的例子
下面给出一个简单的循环服务器样子,模拟服务器对外提供时间服务器,等待客户端到来,并返回给客户端服务器的当前时间。
UDP循环服务器
1 /** UDP循环服务器--server端程序**/ 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <netinet/in.h> 5 #include <time.h> 6 #include <string.h> 7 #include <stdio.h> 8 #define BUFFLEN 1024 9 #define SERVER_PORT 12345 10 int main(int argc, char *argv[]) 11 { 12 int s; //服务器套接字文件描述符 13 struct sockaddr_in local, to; //本地地址 14 time_t now; //时间 15 char buff[BUFFLEN];//收发数据缓冲区 16 int n = 0; 17 int len = sizeof(to); 18 19 //建立UDP套接字 20 s = socket(AF_INET, SOCK_DGRAM, 0); 21 22 //初始化地址 23 memset(&local, 0, sizeof(local)); 24 local.sin_family = AF_INET;//AF_INET协议族 25 local.sin_addr.s_addr = htonl(INADDR_ANY);//任意本地地址 26 local.sin_port = htons(SERVER_PORT);//服务器端口 27 28 //将套接字文件描述符绑定到本地地址和端口 29 int err = bind(s, (struct sockaddr*)&local, sizeof(local)); 30 31 //主处理过程 32 while(1) 33 { 34 memset(buff, 0, BUFFLEN); 35 n = recvfrom(s, buff, BUFFLEN,0,(struct sockaddr*)&to, &len);//接收发送方数据 36 if(n > 0 && !strncmp(buff, "TIME", 4))//判断是否合法接收数据 37 { 38 printf("Get One Client Connect\n"); 39 memset(buff, 0, BUFFLEN); 40 now = time(NULL); 41 sprintf(buff, "%24s\r\n",ctime(&now)); 42 sendto(s, buff, strlen(buff),0, (struct sockaddr*)&to, len);//发送数据 43 } 44 } 45 close(s); 46 47 return 0; 48 }