轉載:http://www.cnblogs.com/lizhenghn/p/3617608.html
在網絡程序里面,通常都是一個服務器處理多個客戶機,為了出個多個客戶機的請求,服務器端的程序有不同的處理方式。本節開始介紹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 }

1 /** UDP循環服務器--client端程序**/ 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 server; //本地地址 14 time_t now; 15 char buff[BUFFLEN]; 16 int n = 0; 17 int len = 0; //地址長度 18 19 //建立UDP套接字 20 s = socket(AF_INET, SOCK_DGRAM, 0); 21 22 //初始化地址接 23 memset(&server, 0, sizeof(server)); 24 server.sin_family = AF_INET;//AF_INET協議族 25 server.sin_addr.s_addr = htonl(INADDR_ANY);//任意本地地址 26 server.sin_port = htons(SERVER_PORT);//服務器端口 27 28 memset(buff, 0, BUFFLEN); 29 strcpy(buff, "TIME"); 30 //發送數據 31 sendto(s, buff, strlen(buff), 0, (struct sockaddr*)&server, sizeof(server)); 32 memset(buff, 0, BUFFLEN); 33 //接收數據 34 len = sizeof(server); 35 n = recvfrom(s, buff, BUFFLEN, 0, (struct sockaddr*)&server, &len); 36 if(n >0) 37 printf("TIME:%s",buff); 38 39 close(s); 40 41 return 0; 42 }
TCP循環服務器

1 /** TCP循環服務器--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 12346 10 #define BACKLOG 5 11 int main(int argc, char *argv[]) 12 { 13 int s_s, s_c; /*服務器套接字文件描述符*/ 14 struct sockaddr_in local, from; /*本地地址*/ 15 time_t now; 16 char buff[BUFFLEN]; 17 int n = 0; 18 int len = sizeof(from); 19 20 /*建立TCP套接字*/ 21 s_s = socket(AF_INET, SOCK_STREAM, 0); 22 23 /*初始化地址*/ 24 memset(&local, 0, sizeof(local)); 25 local.sin_family = AF_INET;/*AF_INET協議族*/ 26 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/ 27 local.sin_port = htons(SERVER_PORT);/*服務器端口*/ 28 29 /*將套接字文件描述符綁定到本地地址和端口*/ 30 int err = bind(s_s, (struct sockaddr*)&local, sizeof(local)); 31 err = listen(s_s, BACKLOG);/*偵聽*/ 32 33 /*主處理過程*/ 34 while(1) 35 { 36 /*接收客戶端連接*/ 37 s_c = accept(s_s, (struct sockaddr*)&from, &len); 38 memset(buff, 0, BUFFLEN); 39 n = recv(s_c, buff, BUFFLEN,0);/*接收發送方數據*/ 40 if(n > 0 && !strncmp(buff, "TIME", 4))/*判斷是否合法接收數據*/ 41 { 42 memset(buff, 0, BUFFLEN); 43 now = time(NULL); 44 sprintf(buff, "%24s\r\n",ctime(&now)); 45 send(s_c, buff, strlen(buff),0);/*發送數據*/ 46 } 47 close(s_c); 48 } 49 close(s_s); 50 51 return 0; 52 }

/**TCP循環服務器--client端程序**/ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string.h> #include <stdio.h>#define BUFFLEN 1024 #define SERVER_PORT 12346 int main(int argc, char *argv[]) {int s; /*服務器套接字文件描述符*/struct sockaddr_in server; /*本地地址*/char buff[BUFFLEN];int n = 0; /*建立TCP套接字*/s = socket(AF_INET, SOCK_STREAM, 0);/*初始化地址*/memset(&server, 0, sizeof(server));server.sin_family = AF_INET;/*AF_INET協議族*/server.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/server.sin_port = htons(SERVER_PORT);/*服務器端口*/ /*連接服務器*/int err = connect(s, (struct sockaddr*)&server,sizeof(server));memset(buff, 0, BUFFLEN);strcpy(buff, "TIME");/*發送數據*/send(s, buff, strlen(buff), 0);memset(buff, 0, BUFFLEN);/*接收數據*/ n = recv(s, buff, BUFFLEN, 0);if(n >0){printf("TIME:%s",buff); }close(s);return 0; }
?
兩者返回給客戶端的的輸出都是一樣的,比如:TIME:Sat Mar 22 15:26:25 2014
?
循環服務器的介紹就到這里。接下來介紹并發服務器模型。