轉載:http://www.cnblogs.com/lizhenghn/p/3617666.html
? 與循環服務器的串行處理不同,并發服務器對服務請求并發處理。循環服務器只能夠一個一個的處理客戶端的請求,顯然效率很低。并發服務器通過建立多個子進程來實現對請求的并發處理。并發服務器的一個難點是如何確定子進程的數據,因為不清楚請求客戶端的數目,因此實現中通常采用事先分配一定數目的子進程與動態增加子進程相結合的方法來實現并發服務器。
簡單并發服務器模型
/* UDP簡單并發服務器模型 */ /* 服務器主進程 */ socket(...); bind(...); fork(); //創建多個子進程進行請求處理 while(1); /* 服務器子進程1 */ while(1) {recvfrom(....);process(...);sendto(.....); } close(...); /* 服務器子進程2(同上) */ .................. .................. .................. /* 服務器子進程3(同上) */ .................. .................. ..................
/* TCP簡單并發服務器模型 */ /* 服務器主進程 */ socket(...); bind(...); fork();//創建多個子進程進行請求處理 while(1); /* 服務器子進程1 */ socket(...); bind(...); listen(...); while(1) {accept(...);recv(....)process(...);send(.....); } close(....); /* 服務器子進程2(同上) */ .................. .................. .................. /* 服務器子進程3(同上) */ .................. .................. ..................
?
一個并發服務器的例子
下面給出一個簡單的并發服務器樣子,仍然模擬服務器對外提供時間服務器,等待客戶端到來,并返回給客戶端服務器的當前時間。
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 12347 10 #define BACKLOG 5 11 12 static void handle_request(int s, struct sockaddr_in* from, char *buff) 13 { 14 time_t now; 15 int len = sizeof(*from); 16 memset(buff, 0, BUFFLEN); 17 now = time(NULL); 18 sprintf(buff, "%24s\r\n",ctime(&now)); 19 sendto(s, buff, strlen(buff),0, (struct sockaddr*)from, len);/*發送數據*/ 20 } 21 22 static void handle_connect(int s_s) 23 { 24 struct sockaddr_in from; /*客戶端地址*/ 25 int len = sizeof(from); 26 int n = 0; 27 char buff[BUFFLEN]; 28 29 /*主處理過程*/ 30 while(1) 31 { 32 memset(buff, 0, BUFFLEN); 33 /*接收客戶端連接*/ 34 n = recvfrom(s_s, buff, BUFFLEN,0,(struct sockaddr*)&from, &len);/*接收發送方數據*/ 35 if(n > 0 && !strncmp(buff, "TIME", 4))/*判斷是否合法接收數據*/ 36 { 37 /*創建進程進行數據處理*/ 38 if(!fork()) 39 { 40 handle_request(s_s, &from, buff);/*處理連接請求*/ 41 return ; 42 } 43 } 44 } 45 } 46 47 48 int main(int argc, char *argv[]) 49 { 50 int s_s; /*服務器套接字文件描述符*/ 51 struct sockaddr_in local; /*本地地址*/ 52 53 /*建立TCP套接字*/ 54 s_s = socket(AF_INET, SOCK_STREAM, 0); 55 56 /*初始化地址接哦股*/ 57 memset(&local, 0, sizeof(local)); 58 local.sin_family = AF_INET;/*AF_INET協議族*/ 59 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/ 60 local.sin_port = htons(SERVER_PORT);/*服務器端口*/ 61 62 /*將套接字文件描述符綁定到本地地址和端口*/ 63 int err = bind(s_s, (struct sockaddr*)&local, sizeof(local)); 64 65 /*處理客戶端連接*/ 66 handle_connect(s_s); 67 68 close(s_s); 69 70 return 0; 71 }
?
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 12347 10 #define BACKLOG 5 11 12 static void handle_request(int s_c) 13 { 14 time_t now; 15 char buff[BUFFLEN]; 16 int n = 0; 17 memset(buff, 0, BUFFLEN); 18 n = recv(s_c, buff, BUFFLEN,0);/*接收發送方數據*/ 19 if(n > 0 && !strncmp(buff, "TIME", 4))/*判斷是否合法接收數據*/ 20 { 21 memset(buff, 0, BUFFLEN); 22 now = time(NULL); 23 sprintf(buff, "%24s\r\n",ctime(&now)); 24 send(s_c, buff, strlen(buff),0);/*發送數據*/ 25 } 26 /*關閉客戶端*/ 27 close(s_c); 28 } 29 30 static void handle_connect(int s_s) 31 { 32 int s_c; /*客戶端套接字文件描述符*/ 33 struct sockaddr_in from; /*客戶端地址*/ 34 int len = sizeof(from); 35 36 /*主處理過程*/ 37 while(1) 38 { 39 /*接收客戶端連接*/ 40 s_c = accept(s_s, (struct sockaddr*)&from, &len); 41 if(s_c > 0)/*客戶端成功連接*/ 42 { 43 /*創建進程進行數據處理*/ 44 if(fork() > 0)/*父進程*/ 45 { 46 close(s_c);/*關閉父進程的客戶端連接套接字*/ 47 } 48 else 49 { 50 handle_request(s_c);/*處理連接請求*/ 51 return ; 52 } 53 } 54 } 55 } 56 57 58 int main(int argc, char *argv[]) 59 { 60 int s_s; /*服務器套接字文件描述符*/ 61 struct sockaddr_in local; /*本地地址*/ 62 63 /*建立TCP套接字*/ 64 s_s = socket(AF_INET, SOCK_STREAM, 0); 65 66 /*初始化地址*/ 67 memset(&local, 0, sizeof(local)); 68 local.sin_family = AF_INET;/*AF_INET協議族*/ 69 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/ 70 local.sin_port = htons(SERVER_PORT);/*服務器端口*/ 71 72 /*將套接字文件描述符綁定到本地地址和端口*/ 73 int err = bind(s_s, (struct sockaddr*)&local, sizeof(local)); 74 err = listen(s_s, BACKLOG);/*偵聽*/ 75 76 /*處理客戶端連接*/ 77 handle_connect(s_s); 78 79 close(s_s); 80 81 return 0; 82 }
?
注意,
1. 為了方便退出,server程序中對信號SIGINT信號進行了處理,此時所有的進程都會退出;
2. 并發服務器中的client程序與上一節介紹循環服務器時使用的client程序是一樣的,這里不在貼出來,
? ? 請參考?Linux網絡編程服務器模型選擇之循環服務器?http://www.cnblogs.com/lizhenghn/p/3617608.html