Linux網絡編程服務器模型選擇之并發服務器(下)

轉載:http://www.cnblogs.com/lizhenghn/p/3618986.html

前面兩篇文章(參見)分別介紹了循環服務器和簡單的并發服務器網絡模型,我們已經知道循環服務器模型效率較低,同一時刻只能為一個客戶端提供服務,而且對于TCP模型來說,還存在單客戶端長久獨占與服務器的連接,無法再響應其他連接,對于前面介紹的并發服務器模型是比較簡單的,比如由于預先分配了固定進程數目,就導致無法動態調整等問題。在前面我們也提到了對accept函數的處理是區分不同服務器模型的一個重要依據,當然UDP服務器并不需要accept函數,因此本次主要介紹TCP的高級并發模型。按照對accept的不同處理,接下來主要介紹以下幾種并發模型:

  1. 單客戶端單進程,統一accept :服務器主進程等待客戶端連接,一旦有連接到來,就創建一個進程用于響應;
  2. 單客戶端單線程,統一accept :服務器主進程等待客戶端連接,一旦有連接到來,就創建一個線程用于響應;
  3. 單客戶端單線程,各自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;        
}
復制代碼

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384323.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384323.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384323.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

劍指Offer05. 替換空格

請實現一個函數&#xff0c;把字符串 s 中的每個空格替換成"%20"。 示例 1&#xff1a; 輸入&#xff1a;s “We are happy.” 輸出&#xff1a;“We%20are%20happy.” class Solution { public:string replaceSpace(string s) {int count0;int lens.size();stri…

Linux網絡編程服務器模型選擇之IO復用循環并發服務器

轉載&#xff1a;http://www.cnblogs.com/lizhenghn/p/3619091.html 在前面我們介紹了循環服務器&#xff0c;并發服務器模型。簡單的循環服務器每次只能處理一個請求&#xff0c;即處理的請求是串行的&#xff0c;效率過低&#xff1b;并發服務器可以通過創建多個進程或者是線…

數據結構(六)二叉樹的遍歷(遞歸非遞歸方法)

數據結構&#xff08;六&#xff09;二叉樹的遍歷&#xff08;遞歸非遞歸方法&#xff09; 一、遞歸方法 1.先序遍歷 void PreOrder(BiTree T) {visit(T);PreOrder(T->LChild)PreOrder(T->RChild) }2.先序遍歷 void PreOrder(BiTree T) {PreOrder(T->LChild)visit…

memcpy/memset函數的c語言實現

轉載&#xff1a;http://blog.csdn.net/u011118276/article/details/46742341 1、memcpy 頭文件&#xff1a;#include <string.h> 函數原型&#xff1a;void *memcpy(void *dest, const void *src, size_t n) 功能&#xff1a;將指針src指向的內存空間的n個字節復制到des…

計算機網絡(一)計算機網絡體系

計算機網絡&#xff08;一&#xff09;計算機網絡體系一、計算機網絡概述概念功能組成分類二、體系結構和參考模型ISO/OSI模型物理層網絡層傳輸層會話層表示層應用層OSI參考模型與TCP/IP參考模型OSI參考模型與TCP/IP參考模型不同5層參考模型一、計算機網絡概述 概念 計算機網…

計算機網絡(二)物理層

計算機網絡&#xff08;二&#xff09;物理層一、通信基礎物理層接口特性1.機械特性2.電氣特性3.功能特性4.規程特性典型的數據通信模型三種通信方式1.單工通信2.半雙工通信/雙向交替通信3.全雙工通信/雙向同時通信數據傳輸方式串行傳輸并行傳輸同步傳輸異步傳輸二、數據交換方…

計算機網絡(三)數據鏈路層

計算機網絡&#xff08;三&#xff09;數據鏈路層1.基本概念2.功能概述3.組幀字符計數法字符填充法零比特填充法違規編碼法4.差錯控制檢錯編碼奇偶校驗碼CRC循環冗余碼糾錯編碼海明碼流量控制停止等待協議滑動窗口協議后退N幀協議&#xff08;GBN&#xff09;選擇重傳協議5.介質…

libevent網絡編程例子(1)

轉載&#xff1a;http://blog.csdn.net/huangyimo/article/details/46806193 這篇文章介紹下libevent在socket異步編程中的應用。在一些對性能要求較高的網絡應用程序中&#xff0c;為了防止程序阻塞在socket I/O操作上造成程序性能的下降&#xff0c;需要使用異步編程&#xf…

計算機網絡(四)網絡層

計算機網絡&#xff08;四&#xff09;網絡層一、概述和功能TCP/IP協議棧IP數據報格式IP數據報分片二、ipv4網絡地址轉換&#xff08;NAT&#xff09;子網劃分子網掩碼ARP協議&#xff08;地址解析協議&#xff09;DHCP協議ICMP協議二、ipv6ipv4和ipv6的區別IPv6基本地址類型IP…

Linux下基于socket和多線程的聊天室小程序

轉載&#xff1a;http://blog.csdn.net/robot__man/article/details/52460733 要求&#xff1a;基于TCP編寫&#xff0c;一個聊天室最多100人。 客戶端&#xff1a;   1、用戶需要登錄&#xff0c;登錄時只需要輸入一個昵稱即可無需判斷昵稱是否重復&#xff08;如果其他功…

操作系統(一)計算機系統概述

操作系統&#xff08;一&#xff09;計算機系統概述一、操作系統的概念二、功能和目標資源的管理者向上層提供服務對硬件的擴展三、操作系統的特征并發共享虛擬異步四、操作系統的發展與分類手工操作階段批處理階段單道批處理系統多道批處理系統分時操作系統實時操作系統操作系…

Linux下使用socket傳輸文件的C語言簡單實現

轉載&#xff1a;http://blog.csdn.net/ljd_1986413/article/details/7940938 服務器程序和客戶端程序應當分別運行在兩臺計算機上。 在運行服務器端的計算機終端執行&#xff1a;./file_server 在運行客戶端的計算終端上執行&#xff1a;./file_client ipaddr_server 然后根…

操作系統(二)進程管理

ui 操作系統&#xff08;二&#xff09;進程管理一、進程程序和進程進程控制塊&#xff08;PCB&#xff09;進程的組成進程的特征進程的狀態與轉換進程狀態的轉換進程的組織鏈接方式索引方式進程的控制進程的創建進程的終止進程阻塞進程喚醒進程切換進程通信共享存儲消息傳遞管…

gethostbyname()函數說明

轉載&#xff1a;http://www.cnblogs.com/cxz2009/archive/2010/11/19/1881611.html gethostbyname()函數說明——用域名或主機名獲取IP地址 包含頭文件 #include <netdb.h> #include <sys/socket.h> 函數原型 struct hostent *gethostbyna…

操作系統(三)內存管理

操作系統&#xff08;三&#xff09;內存管理一、程序執行過程裝入的三種方式鏈接的三種方式二、內存管理的概念內存空間的分配與回收連續分配管理方式單一連續分配固定分區分配動態分區分配首次適應算法最佳適應算法最壞適應算法鄰近適應算法非連續分配管理方式基本分頁存儲管…

操作系統(四)文件管理

操作系統&#xff08;四&#xff09;文件管理一、文件系統基礎1.文件邏輯結構無結構文件有結構文件2.文件目錄文件控制塊&#xff08;FCB&#xff09;目錄結構單級目錄兩級目錄結構多級目錄結構無環圖目錄結構3.文件保護口令保護加密保護訪問控制4.文件共享硬鏈接軟鏈接5.文件系…

struct stat結構體簡介

轉載&#xff1a;http://www.cnblogs.com/CSU-PL/archive/2013/06/06/3120757.html 在使用這個結構體和方法時&#xff0c;需要引入&#xff1a; <sys/types.h> <sys/stat.h> struct stat這個結構體是用來描述一個linux系統文件系統中的文件屬性的結構。 可以有兩種…

如何在Ubuntu上安裝GCC編譯器

如何在Ubuntu上安裝GCC編譯器1.首先更新包列表sudo apt update2.安裝build-essential軟件包&#xff1a; sudo apt install build-essential3.驗證GCC編譯器是否已成功安裝&#xff0c;請使用gcc --version命令打印GCC版本 rootubuntu:/home/csd# gcc --version

操作系統(五)輸入/輸出(I/O)管理

操作系統&#xff08;五&#xff09;輸入/輸出&#xff08;I/O&#xff09;管理一、I/O控制器二、I/O控制方式程序直接控制方式中斷驅動方式DMA方式通道控制方式I/O軟件層次結構假脫機技術設備的分配與回收緩沖區單緩沖雙緩沖循環緩沖區緩沖池一、I/O控制器 I/O設備由機械部件…

Linux下的I/O多路復用select,poll,epoll淺析

轉載&#xff1a;http://blog.csdn.net/u011573853/article/details/52105365 一&#xff0c;什么是I/O多路復用 所謂的I/O多路復用在英文中其實叫 I/O multiplexing. 就是單個線程&#xff0c;通過記錄跟蹤每個I/O流(sock)的狀態&#xff0c;來同時管理多個I/O流 。) I/O mu…