轉載:http://www.cnblogs.com/lizhenghn/p/3618986.html
前面兩篇文章(參見)分別介紹了循環服務器和簡單的并發服務器網絡模型,我們已經知道循環服務器模型效率較低,同一時刻只能為一個客戶端提供服務,而且對于TCP模型來說,還存在單客戶端長久獨占與服務器的連接,無法再響應其他連接,對于前面介紹的并發服務器模型是比較簡單的,比如由于預先分配了固定進程數目,就導致無法動態調整等問題。在前面我們也提到了對accept函數的處理是區分不同服務器模型的一個重要依據,當然UDP服務器并不需要accept函數,因此本次主要介紹TCP的高級并發模型。按照對accept的不同處理,接下來主要介紹以下幾種并發模型:
- 單客戶端單進程,統一accept :服務器主進程等待客戶端連接,一旦有連接到來,就創建一個進程用于響應;
- 單客戶端單線程,統一accept :服務器主進程等待客戶端連接,一旦有連接到來,就創建一個線程用于響應;
- 單客戶端單線程,各自accept :預先分配多個線程,在每一個線程里都獨自等待客戶端的連接并響應(注意accept需要互斥訪問);
并發模型偽代碼
/* 單客戶端單進程,統一accept */ /* 服務器主進程 */socket();bind();listen();while(1){accept();fork();//子進程 }close(); //關閉服務器端套接字/* 服務器子進程1 */ recv();process();send();close();//關閉客戶端套接字/* 服務器子進程2(同上) */ ..................
/* 單客戶端單線程,統一accept */ /* 服務器主進程 */socket();bind();listen();while(1){accept();pthread_create(); //創建響應線程 }close();//關閉服務器端套接字/* 服務器線程1 */ recv(); process(); send(); close();//關閉客戶端套接字 /* 服務器線程2(同上) */ ..................
/* 單客戶端單線程,各自accept */ /* 服務器主進程 */socket();bind();listen();pthread_create();//創建多個線程分別等待客戶端連接pthread_join();//等待線程結束close();//關閉服務器端套接字/* 服務器線程1 */ mutex_lock()//互斥鎖 accept(); mutex_unlock();recv(); process(); send(); close();//客戶端套接字 /* 服務器線程2(同上) */ ..................
一個高級并發服務器模型的例子
單客戶端單進程,統一accept server端程序
1 /* 單客戶端單進程,統一accept --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 12348 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 33 int s_c; /*客戶端套接字文件描述符*/ 34 struct sockaddr_in from; /*客戶端地址*/ 35 int len = sizeof(from); 36 37 /*主處理過程*/ 38 while(1) 39 { 40 s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客戶端連接*/ 41 if(s_c > 0)/*客戶端成功連接,創建進程進行數據處理*/ 42 { 43 if(fork() > 0) /*父進程*/ 44 { 45 close(s_c); /*關閉父進程的客戶端連接套接字*/ 46 } 47 else 48 { 49 handle_request(s_c);/*處理連接請求*/ 50 } 51 } 52 } 53 } 54 55 int main(int argc, char *argv[]) 56 { 57 int s_s; /*服務器套接字文件描述符*/ 58 struct sockaddr_in local; /*本地地址*/ 59 60 /*建立TCP套接字*/ 61 s_s = socket(AF_INET, SOCK_STREAM, 0); 62 63 /*初始化地址*/ 64 memset(&local, 0, sizeof(local)); 65 local.sin_family = AF_INET;/*AF_INET協議族*/ 66 local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/ 67 local.sin_port = htons(SERVER_PORT);/*服務器端口*/ 68 69 /*將套接字文件描述符綁定到本地地址和端口*/ 70 int err = bind(s_s, (struct sockaddr*)&local, sizeof(local)); 71 err = listen(s_s, BACKLOG);/*偵聽*/ 72 73 /*處理客戶端連接*/ 74 handle_connect(s_s); 75 76 close(s_s); 77 78 return 0; 79 }
單客戶端單進程,統一accept server端程序
1 單客戶端單線程,統一accept server端程序 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <netinet/in.h> 5 #include <time.h> 6 #include <string.h>
#include <pthread> 7 #include <stdio.h> 8 #define BUFFLEN 1024 9 #define SERVER_PORT 12348 10 #define BACKLOG 5 11 12 static void *handle_request(void *argv) 13 { 14 int s_c = *((int*)argv); 15 time_t now; 16 char buff[BUFFLEN]; 17 int n = 0; 18 memset(buff, 0, BUFFLEN); 19 n = recv(s_c, buff, BUFFLEN,0); 20 if(n > 0 && !strncmp(buff, "TIME", 4)) 21 { 22 memset(buff, 0, BUFFLEN); 23 now = time(NULL); 24 sprintf(buff, "%24s\r\n",ctime(&now)); 25 send(s_c, buff, strlen(buff),0); 26 } 27 28 close(s_c); /*關閉客戶端*/ 29 } 30 31 static void handle_connect(int s_s) 32 { 33 int s_c; /*客戶端套接字文件描述符*/ 34 struct sockaddr_in from; /*客戶端地址*/ 35 int len = sizeof(from); 36 pthread_t thread_do; 37 38 /*主處理過程*/ 39 while(1) 40 { 41 s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客戶端連接*/ 42 if(s_c > 0)/*客戶端成功連接,創建線程進行數據處理*/ 43 { 44 int err = pthread_create(&thread_do,NULL,handle_request,(void*)&s_c; 45 } 46 } 47 } 48 49 int main(int argc, char *argv[]) 50 { 51 int s_s; /*服務器套接字文件描述符*/ 52 struct sockaddr_in local; /*本地地址*/ 53 54 s_s = socket(AF_INET, SOCK_STREAM, 0);/*建立TCP套接字*/ 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 err = listen(s_s, BACKLOG);/*偵聽*/ 65 66 /*處理客戶端連接*/ 67 handle_connect(s_s); 68 69 close(s_s); 70 71 return 0; 72 }
單客戶端單線程,各自accept?--server端程序
/** 單客戶端單線程,各自accept --server端程序 */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <time.h> #include <string.h> #include <stdio.h> #include <pthread> #define BUFFLEN 1024 #define SERVER_PORT 12348 #define BACKLOG 5 #define CLIENT_NUM 3pthread_mutex_t g_lock = PTHREAD_MUTEX_INTIALIZER;static void *handle_request(void *argv) {int s_s = *((int*)argv); //服務器端套接字struct sockaddr_in from; /*客戶端地址*/int len = sizeof(from);int s_c = -1; //客戶端套接字for( ; ; ){time_t now; char buff[BUFFLEN];int n = 0;memset(buff, 0, BUFFLEN);pthread_mutex_lock(&g_lock);s_c = accept(s_s,(struct sockaddr*)&from, &len);pthread_mutex_unlock(&g_lock); n = recv(s_c, buff, BUFFLEN,0);if(n > 0 && !strncmp(buff, "TIME", 4)){memset(buff, 0, BUFFLEN);now = time(NULL);sprintf(buff, "%24s\r\n",ctime(&now));send(s_c, buff, strlen(buff),0);}close(s_c); /*關閉客戶端*/}return NULL; }static void handle_connect(int s_s) { int s_s = s;pthread_t thread_do[CLIENT_NUM];for(int i=0; i<CLIENT_NUM;++i){int err = pthread_create(&thread_do[i],NULL,handle_request,(void*)&s_s;}//等待線程結束for(int i=0; i<CLIENT_NUM;++i)pthread_join(thread_do[i],NULL); }int main(int argc, char *argv[]) {int s_s; /*服務器套接字文件描述符*/struct sockaddr_in local; /*本地地址*/ s_s = socket(AF_INET, SOCK_STREAM, 0);/*建立TCP套接字*//*初始化地址*/memset(&local, 0, sizeof(local));local.sin_family = AF_INET;/*AF_INET協議族*/local.sin_addr.s_addr = htonl(INADDR_ANY);/*任意本地地址*/local.sin_port = htons(SERVER_PORT);/*服務器端口*//*將套接字文件描述符綁定到本地地址和端口*/int err = bind(s_s, (struct sockaddr*)&local, sizeof(local));err = listen(s_s, BACKLOG);/*偵聽*/handle_connect(s_s);/*處理客戶端連接*/close(s_s);return 0; }