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

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

在前面我們介紹了循環服務器,并發服務器模型。簡單的循環服務器每次只能處理一個請求,即處理的請求是串行的,效率過低;并發服務器可以通過創建多個進程或者是線程來并發的處理多個請求。但是當客戶端增加時,就需要創建更多的進程或者線程,就會導致系統負載最終轉移到進程或線程的切換開銷上。

????? 為了減少這類開銷,而使系統處理能力集中在核心業務上,就要求我們降低并發的進程或線程數目,因此又實現了一個更高級的IO復用循環服務器。I/O復用的循環服務器一般創建兩個線程,一個是客戶端連接處理線程,專門用來處理客戶端的連接,當有客戶端到來的時候,此線程把客戶端的套接字描述符放到一塊公共的區域中。另一個是業務處理線程,此線程輪循(select)客戶端套接字描述符集合中有沒有數據到來,如果有數據到來,那么就進行處理。這樣,客戶 端的增加并不會造成系統進程或線程數的明顯增加,而使其處理能力與CPU和內存直接相關。

TCP并發服務器模型 I/O多路復用模型偽代碼

復制代碼
/* TCP并發服務器模型 I/O多路復用 */  
/* 服務器主進程 */socket();bind();listen();      pthread_create( ); //創建客戶端連接線程和業務處理線程pthread_join( ); //等待線程結束close( ); //關閉服務器套接字  
/* 連接處理線程 */while(1){accept( ); //接受一個客戶端連接store();//存儲客戶端套接字描述符到一個公共集合中
  }/* 業務處理線程 */while(1){get( ); //取出可用的客戶端套接字描述符select( ); //設置監聽讀寫文件描述符集合
      recv( );process( );send( );close( );}
復制代碼

一個I/O多路復用模型的例子

復制代碼
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/select.h>
#define BUFFLEN 1024
#define SERVER_PORT 12349
#define BACKLOG 5  
#define CLIENTNUM 1024 /**最大支持客戶端數量*//*可連接客戶端的文件描述符數組*/
int connect_host[CLIENTNUM];
int connect_number =  0;
static void *handle_request(void *argv)
{    time_t now;        /*時間*/char buff[BUFFLEN];/*收發數據緩沖區*/int n = 0;int maxfd = -1;/*最大偵聽文件描述符*/fd_set scanfd;    /*偵聽描述符集合*/struct   timeval   timeout;     /*超時*/timeout.tv_sec     =   1; /*   阻塞1秒后超時返回   */     timeout.tv_usec   =   0;     int i = 0;int err  = -1;for(;;){   /*最大文件描述符值初始化為-1*/        maxfd = -1;FD_ZERO(&scanfd);/*清零文件描述符集合*/for(i=0;i<CLIENTNUM;i++)/*將文件描述符放入集合*/{if(connect_host[i] != -1)/*合法的文件描述符*/{FD_SET(connect_host[i], &scanfd);/*放入集合*/if(maxfd <     connect_host[i])/*更新最大文件描述符值*/{maxfd = connect_host[i];}}}/*select等待*/err = select(maxfd + 1, &scanfd, NULL, NULL, &timeout) ;        switch(err){case 0:/*超時*/break;case -1:/*錯誤發生*/break;default:/*有可讀套接字文件描述符*/if(connect_number<=0)break;for(i = 0;i<CLIENTNUM;i++){/*查找激活的文件描述符*/if(connect_host[i] != -1)if(FD_ISSET(connect_host[i],&scanfd))   {  memset(buff, 0, BUFFLEN);/*清零*/n = recv(connect_host[i], 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(connect_host[i], buff, strlen(buff),0);/*發送數據*/}/*關閉客戶端*/close(connect_host[i]);    /*更新文件描述符在數組中的值*/connect_host[i] = -1;connect_number --;    /*客戶端計數器減1*/                                                    } }break;     }          } return NULL;
}static void *handle_connect(void *argv)
{    int s_s = *((int*)argv) ;/*獲得服務器偵聽套接字文件描述符*/int s_c = -1;/*連接客戶端文件描述符*/struct sockaddr_in from;int len = sizeof(from);/*接收客戶端連接*/for(;;){int i = 0;int s_c = accept(s_s, (struct sockaddr*)&from, &len);/*接收客戶端的請求*/printf("a client connect, from:%s\n",inet_ntoa(from.sin_addr));/*查找合適位置,將客戶端的文件描述符放入*/                for(i=0;i<CLIENTNUM;i++){if(connect_host[i] == -1)/*找到*/{/*放入*/connect_host[i]= s_c;/*客戶端計數器加1*/connect_number ++;/*繼續輪詢等待客戶端連接*/break;                        }    }        }    return NULL;
}int main(int argc, char *argv[])
{int s_s;    /*服務器套接字文件描述符*/struct sockaddr_in local;    /*本地地址*/    int i = 0;memset(connect_host, -1, CLIENTNUM);/*建立TCP套接字*/s_s = socket(AF_INET, SOCK_STREAM, 0);/*初始化地址接哦股*/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);/*偵聽*/pthread_t  thread_do[2];/*線程ID*//*創建線程處理客戶端連接*/pthread_create(&thread_do[0],/*線程ID*/NULL,/*屬性*/handle_connect,/*線程回調函數*/(void*)&s_s);        /*線程參數*//*創建線程處理客戶端請求*/                    pthread_create(&thread_do[1],/*線程ID*/NULL,/*屬性*/handle_request,/*線程回調函數*/NULL);        /*線程參數*//*等待線程結束*/for(i=0;i<2;i++)pthread_join(thread_do[i], NULL);close(s_s);return 0;        
}
復制代碼

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

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

相關文章

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

數據結構&#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…

計算機組成原理(一)計算機系統概述

計算機組成原理&#xff08;一&#xff09;計算機系統概述一、計算機系統層次結構馮諾伊曼機計算機工作過程多級層次結構一、計算機系統層次結構 馮諾伊曼機 特點&#xff1a; 計算機由五大部件組成指令和數據以同等地位存于存儲 器&#xff0c;可按地址尋訪指令和數據用二進…

計算機組成原理(二)數據的表示和運算

計算機組成原理&#xff08;二&#xff09;數據的表示和運算一、BCD碼二、奇偶校驗碼三、海明碼四、循環冗余校驗碼&#xff08;CRC&#xff09;五、乘法運算原碼乘法補碼乘法六、除法運算原碼除法補碼除法七、浮點數的表示與運算浮點數的運算一、BCD碼 組合式BCD碼&#xff1…