服務器一般分為如下三個主要模塊:I/O處理單元(四種I/O模型,兩種高效事件處理模塊),邏輯單元(兩種高效并發模式,有效狀态機)和存儲單元(不讨論)。
C/S模型
結構:
特點:
邏輯簡單。
工作流程:
I/O複用技術:select,同時監聽多個客戶請求。
優點:适合資源相對集中的場合。
缺點:當訪問量過大,可能所有客戶都将得到很慢的相應。
P2P模型
結構:兩種結構
結構b比結構a增加了發現服務器,用于主機之間的互相發現,盡快找到自己需要的資源。
特點:
摒棄了服務器為中心的格局,讓網絡上所有主機處于對等的地位。
每台機器在消耗服務的同時也給别人提供服務
缺點:當用戶之間傳輸的請求過多時,網絡的負載将加重
基本框架:
模塊說明:
阻塞I/O
socket在創建的時候是阻塞的。我們可以給socket系統調用的第2個參數傳遞SOCK_NONBLOCK 标志,或者通過fcntl 系統調用的F_SETFL 命令,将其設置為非阻塞。
阻塞模型和非阻塞模型:
阻塞I/O:阻塞的文件描述符,系統調用可能因為無法立即完成而被操作系統挂起。
例如:客戶端connect發起連接,服務器相應之前的這段時間,connect調用将被挂起,直到确認報文段到達将之喚起。
可能被阻塞的系統調用包括accept,send,recv和connect 。
非阻塞I/O:非阻塞的文件描述符,總是立即返回,不管時間是否發生。
如果事件沒有立即發生,這些系統調用返回-1,這時我們就要确認是延遲還是出錯,此時我們必須根據errno來區分這兩種情況。
對accept.send和recv而言,事件未發生時errno通常被設置成EAGAIN(再來一次)或者EWOULDBLOCK(期望阻塞);對connect而言,errno則被設置成EINPROGRESS(在處理中)。
注意:通常情況下,非阻塞I/O要和其他I/O通知機制一起使用才能提高程序的效率。
I/O複用
常用:I/O通知機制
描述:應用程序通過I/O複用函數向内核注冊一組事件,内核通過I/O複用函數把其中就緒的事件通知應用程序。
I/O複用函數:select、poll和epoll_wait,後面的章節會讨論這些函數。
注意:I/O複用函數本身是阻塞的,它們能提高程序效率的原因在于它們具有同時監聽多個I/O事件的能力。
SIGIO信号
作用:報告I/O事件
描述:我們可以為一個目标文件描述符指定宿主進程,那麼指定的宿主進程将捕獲到SIGIO信号。這樣,當目标文件描述符上有事件發生時,SIGIO信号的信号處理函數将被觸發,我們也就可以在該信号處理函數中對目标文件描述符執行非阻塞I/O操作了。
異步I/O模型
上面讨論的三種模型都屬于同步I/O模型
同步I/O模型和異步I/O模型的區别
同步:I/O的讀寫操作發生在I/O事件之後,由應用程序(用戶代碼)來完成。
異步:異步I/O的讀寫操作總是立即返回的,不論I/O事件是否被阻塞,因為真正的讀寫操作被内核接管,即内核來執行I/O操作,具體表現為數據在内核緩沖區和用戶緩沖區之間的移動。
可以認為,同步I/O向應用程序通知I/O就緒事件,異步I/O向應用程序通知I/O完成事件(可能并沒有真正的完成)。
I/O模型對比如下:
服務器程序通常需要處理三類事件:I/O事件,信号和定時事件。後面會一次介紹。
這一節先介紹兩種高效的事件處理模式:Reactor(同步I/O模型)和Proactor(異步I/O模型)。
Reactor模式
描述:
流程:
使用同步I/O模型(以epoll_wait為例)實現的Reactor模式的工作流程是:
流程圖如下:
Proactor模式
描述:将所有I/O操作都交給主線程和内核來處理,工作線程僅僅負責業務邏輯。更符合之前提到的服務器編程框架。
流程:使用異步I/O模型(以aio_read和aio_write為例)實現Proactor模式的工作流程是:
流程圖如下:
連接socket上的讀寫事件是通過aio_read/aio_write 向内核注冊的,因此内核将通過信号來向應用程序報告連接socket上的讀寫事件。所以,主線程中的epoll_wait調用僅能用來檢測監聽socket 上的連接請求事件,而不能用來檢測連接socket 上的讀寫事件。
同步I/O方式模拟Proactor模式
原理:主線程執行數據讀寫操作,讀寫完成之後,主線程向工作線程通知這一“完成事件”,工作線程處理後續邏輯。
流程:
流程圖如下:
并發模式适合:I/O密集型任務
方式:多進程和多線程(後面讨論)
描述:并發模式是指I/O處理單元和多個邏輯單元之間協調完成任務的方法。
服務器主要有兩種并發編程模式:
半同步/半異步模式
解釋:這裡的“同步”和“異步”
同步:程序完全按照代碼序列的順序執行
異步:程序的執行需要由系統事件來驅動,這裡的系統事件包括中斷、信号等。
同步線程:按照同步方式運行的線程稱為同步線程
異步線程:按照異步方式運行的線程稱為異步線程
半同步/半異步模式:同步線程用于處理客戶邏輯,異步線程用于處理I/O事件。
半同步/半反應堆模式
結合考慮兩種事件處理模式(Reactor和Proactor)和幾種I/O模型(阻塞I/O,I/O複用,SIGIO信号,異步I/O),則半同步/半異步就存在多種變體
半同步/半反應堆模式就是其中的一種。
如下圖所示:
特點:
描述:多個工作線程輪流獲得事件源集合,輪流監聽、分發并處理事件的一種模式。
關鍵:領導者的變換和I/O事件的處理
實現:在任意時間點,程序都僅有一個領導者線程, 它負責監聽I/O事件,而其他線程都是追随者,它們休眠在進程池等待成為新的領導者。當前領導者如果檢測到I/O事件,首先要從線程池中推選出新的領導者線程,然後處理I/O事件。
結構:
說明:
句柄集:表示I/O資源,在Linux下通常就是一個文件描述符。
線程集:所有工作線程的管理者。負責各線程之間的同步和新領導者線程的推選。
事件處理器及其子類: 用回調函數的方式處理某事件發生時對應的業務。
工作流程:
To be continued:後面的專題将介紹有限狀态機和提高服務器性能的一些建議
小結:這篇主要介紹了服務器方面的核心框架和設計模式,是這個系列的核心。後續的篇幅都是實現這些模型的技術相關的介紹。
服務器編程的路很深,但技術方面也是穩定的,不像前端技術那樣技術革新很頻繁和有趣。
來源:CSDN
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!