理解計算機系統_并發編程(3)_基于I/O復用的并發(二):基于I/O多路復用的并發事件驅動服務器

前言
? ? ? ?

? ? ? ? 以<深入理解計算機系統>(以下稱“本書”)內容為基礎,對程序的整個過程進行梳理。本書內容對整個計算機系統做了系統性導引,每部分內容都是單獨的一門課.學習深度根據自己需要來定

引入?

? ? ? ? 接續上一帖理解計算機系統_并發編程(2)_基于I/O復用的并發(一):select淺解-CSDN博客,實現一個基于I/O多路復用的并發事件驅動服務器.研讀代碼,總結編程的一些模式.

狀態機

? ? ? ? 本書P686和P687介紹了狀態機的概念并配圖

? ? ? ? 在事件驅動程序中,某些事件會導致流向前推進.一般思路是將邏輯流模型化為狀態機.一個狀態機就是一組狀態,輸入事件轉移,其中轉移是將狀態和輸入事件映射到狀態.---黑體字是原話

? ? ? ? ---解讀:邏輯是什么?是一種因果關系.邏輯流解釋為從因到果的流程.狀態機和邏輯流相互對應

? ? ? ? 狀態對應邏輯(因果),表述為:當條件A滿足時,用事件B響應.

? ? ? ? 輸入事件對應起因已滿足,表述為:條件A已滿足

? ? ? ? 轉移對應用結果響應,表述為:事件B

? ? ? ? /*書面敘述概念時,常用較大的篇幅來寫.而讀者理解時可以采用簡單的方式*/.

? ? ? ? 所有的邏輯都可以轉化成狀態機?

????????狀態機的推導:"狀態"是邏輯是想法,不需要代碼;"輸入事件"和"轉移"需要代碼表達.所以狀態機可以看作是一種理想的邏輯表達方式,從思路到實現都包含了進去.

服務器I/O多路復用的狀態機

? ? ? ? 本書P687第3段:服務器使用I/O多路復用,借助select函數檢測輸入事件的發生.當每個已連接描述符準備好可讀時,服務器就為相應的狀態機執行轉移,在這里就是從描述符讀和寫回一個文本行.

? ? ? ? ---解讀:select:檢測輸入事件;? 轉移:描述符讀和寫回一個文本行.

? ? ? ? 任何一個狀態機必然有檢測輸入事件,這里用的是select函數. 這里的轉移事件---"描述符讀和寫回一個文本行"非必須,演示用.

基于I/O多路復用的并發事件驅動服務器

=============================內容分割線↓===================================

讀代碼的說明

? ? ? ? ?/*代碼是最有說服力的,表現編程思想和程序模型的存在*/

? ? ? ? ?學習別人的源碼,除了理解別人的思路,還要一點也很重要:從源碼中整理和提取寫代碼的模式.

? ? ? ? ?注意:讀代碼的順序是從主程序開始讀,先理解大概意思,再去理解他調用的函數.同樣道理,遇到變量,也不要一個一個挨著去讀,要結合使用去理解.

=============================內容分割線↑===================================

代碼整體說明

? ? ? ? 本書P687最后一段是基于I/O多路復用的并發服務器示例代碼的整體說明.

????????/*如果自己寫了一段代碼,技術文檔也可以借鑒這種方式,讓別人容易理解*/

? ? ? ? 一個pool結構里維護著活動客戶端的集合(第3~11行)? ---黑體字是原話

? ? ? ? ---解讀:這里有個詞叫"維護",經常在其他技術文獻中看到什么維護著什么,感覺很專業.從內容上看,維護代表"描述"或者"控制".

????????活動客戶端的集合在服務器端用一個結構來描述,結構取名叫pool(池),理解為客戶端連接池.

? ? ? ? 然后是初始化init_pool,進入while循環,檢測輸入事件,連接請求到達,調用add_client函數,送回文本.這些內容要簡單了解后,邊讀源碼邊理解.

代碼研讀

? ? ? ? ?注意:經典書的經典代碼,很難得(好好看好好學)

? ? ? ? ?主程序在本書P687和P688,名為echoservers.c

函數開始

? ? ? ? ? 1>第3~11行是"連接池"結構聲明

typedef struct{int maxfd;fd_set read_set;fd_set ready_set;int nready;int maxi;int clientfd[FD_SETSIZE];rio_t clientrio[FD_SETSIZE];
}pool;

? ? ? ? ?如前所述,不用一下全看完,邊讀代碼邊看連接池結構是怎樣定義的.

? ? ? ? ?2>進入main函數,第17~20行是變量定義,也是結合后面代碼讀.注意pool定義為靜態變量,即表示不想被別的模塊使用,如果要用到,必須提供接口.---這是C語言基礎.這里加上了static,聲明成main函數中的局部靜態變量,為了保持更新.

????????注意這里的命名方式不太合理,類型名和變量名取得一樣.規則寫法應該把類型名寫成首字母大寫Pool.

? ? ? ? 3>第26行調用Open_listenfd函數

? ? ? ? ?這里再梳理一遍監聽描述符的建立:Open_listenfd函數是由服務器調用,表示等待客戶端連接請求.一旦客戶端發來連接請求,代碼才執行,生成listenfd監聽描述符,代表服務器已經知道你的請求了.后續將視情況調用accept接受請求,生成connfd描述符.

init_pool函數

? ? ? ? 在本書P688圖12-9.從名字看來表示:初始化連接池.

? ? ? ? 第4~7行代碼如下

int i;
p->maxi=-1;
for(i=0;i<FD_SETSIZE;i++)p->clentfd[i]=-1;

? ? ? ? ---解讀:clientfd[FD_SETSIZE]是第一個理解的數據,他是什么意思?書上說了clientfd數組表示已連接描述符的集合.

? ? ? ? /*已連接描述符在服務器端通常用connfd,書上用了clientfd來表示連接(客戶端連接),connfd用到了其他地方*/

????????開始時沒有連接進來,所以數組中所有整數值設置為-1.-1表示槽位(用其他值也可以,不一定是-1,但既然其值用來表示描述符,所以推薦小于-1的值和其他文件描述符做區分)

? ? ? ??FD_SETSIZE,本書沒有顯式說明.從全大寫的表示來看,他是#define宏定義的一個常數.字面意思代表了允許連接數.

? ? ? ? maxi:已連接集合里的最大索引.初始時沒有連接,也被設置為-1.

? ? ? ? 筆者開始時在這里也饒了半天,這個數組的來源是這樣的,演示如下:

????????服務器每當建立一個連接,就會生成一個描述符connfd來傳輸數據,描述符是個整型數據(從4開始).那么當前有多少個描述符已建立呢?這些描述符該怎樣控制其數量呢?設計了一個整型數組

typedef struct{...int maxi;                 //當前已連接描述符的個數-1,同時也是下面數組中不等于-1的索引值int clientfd[FD_SETSIZE]; //已連接描述符數組,最大連接數限制為FD_SETSIZE...
}pool;

? ? ? ? 初始化時,clientfd[FD_SETSIZE]={-1,-1.....-1},此時索引maxi設置-1.

????????當有一個描述符(比如4)被產生,寫個算法讓他進去數組中,此時clientfd[FD_SETSIZE]={4,-1.....-1},maxi加1,等于0.當遍歷這個數組查詢時,就知道有1個元素(索引等于0)

? ? ? ? 這樣是不是把意思表達清晰了?而這個把數組索引maxi單獨表達的寫法,也值得一學.

? ? ? ? 第10~12行代碼如下????????

p->maxfd=listenfd;
FD_ZERO(&p->read_set);
FD_SET(listenfd,&p->read_set);

? ? ? ---解讀:maxfd是讀集合的基數,"讀集合"和"基數"意思在理解計算機系統_并發編程(2)_基于I/O復用的并發(一):select淺解-CSDN博客有,此處不多說.

? ? ? ? FD_ZERO清空讀集合,FD_SET把listenfd添加到讀集合中. ---初始化配置讀集合?

回到主函數

? ? ? ? 第29行進入while循環,第30行設置"準備好集合",第31行調用Select函數

? ? ? ? ?再看pool中對應數據的使用:

? ? ? ? ?read_set:讀集合;

? ? ? ? ?ready_set:準備好集合.

? ? ? ? ?nready:準備好集合中元素的個數

? ? ? ? ?第35行調用FD_ISSET傳入listenfd,表示連接判定---如果有客戶端請求連接,則執行.

? ? ? ? ?第36行的意思在本書前面一章(筆者也沒有細讀,照著用)

? ? ? ? ?第37行調用Accept函數,表示服務器端同意連接,生成connfd描述符(寫法也參照前面一章)

add_client()函數

? ? ? ? 添加一個新的客戶端到活動客戶端池中,更新pool結構中的數據.

=============================內容分割線↓===================================

? ? ? ? 注意select函數的解讀,他的第一次調用和多次調用的返回值不同.

? ? ? ? 當第一次被調用,也就是maxfd+1=4的情況下,此時讀集合只有一種情況響應---第一個連接請求進來,listenfd描述符被激活.這種情況下p->nready等于1.而如果select函數非第一次調用,表示他可能會有新的連接,或者已有連接準備好讀,這時的p->nready不等于1.---代碼要考慮滿足多種情況.

=============================內容分割線↑===================================

? ? ? ? 第4行更新p->nready,添加描述符到客戶端池的時候,準備好集合的元素個數-1.

? ? ? ? 第5~8行查找槽位,把生成的connfd描述符寫入clientfd數組.

????????注意第6行的if(p->clientfd[i]<0)不是唯一寫法,因為在init_pool的定義中clientfd數組中的值都等于-1.而生成的connfd的值都是≥4的,所以寫成if(p->clientfd[i]==-1)也可以.

? ? ? ? 第9行初始化讀緩沖區,這部分內容沒有細說,可以"抄".這里有個clientrio數組,是分配給每個連接的緩沖區.

? ? ? ? ?第12行把connfd添加進讀集合,意思是下次調用select可以作為條件進入準備好集合.

? ? ? ? ?第15,16行更新maxfd,當讀集合添加了一個描述符后,其基數應該加1.這里用了一個比較

? ? ? ? ?第17,18行更新maxi,"順勢"使新進入的連接作為準備好集合的一員,參加后面的代碼,更新準備好集合的索引

? ? ? ? ?第21行可不寫,寫了更明確:如果i==FD_SETSIZE,超出最大連接數,add_client函數執行無效

check_clients()函數

? ? ? ? ? /*主函數中已沒有其他內容,check_clients()函數緊跟add_client()函數.*/

? ? ? ? ? ?本書P690中間有注釋:check_clients服務準備好的客戶端連接.遍歷clientfd數組,取出文件描述符并讀寫,不詳述.

? ? ? ? ? ?注意:

? ? ? ? ? ? 第7行的for條件中p->nready>0,表示第一次添加進準備好集合(上面17,18行的描述)不能進入這個環節.

????????????第12行的connfd>0筆者沒看懂,以為每個connfd都要≥4(可能有些東西沒完全搞懂),

????????????第12行的FD_ISSET(connfd,&p->ready_set)判斷遍歷出來的connfd是否是本次select執行的結果,以此作為后面代碼執行的前提.從這里可以反推出select函數執行的結果是類似于{1,3,5}這樣的整型數組.

? ? ? ? ? ? /*語法上使用if或者for,while做條件判斷時,如果有多重判斷,值得注意他的意思*/

I/O多路復用技術的優劣

? ? ? ? 以下黑體字是本書原話

? ? ? ? 1.基于事件驅動,聽起來很好,為客戶端提供他們需要的服務,對于基于進程的并發服務器來說,是很困難的.

? ? ? ? ?2.編碼復雜.我們的事件驅動的并發echo服務器需要的代碼比基于進程的服務器多三倍,并且很不行,隨著并發粒度的減小,復雜性還會上升.

? ? ? ? ?3.不能充分利用多核處理器.

代碼層面的小結

? ? ? ? 1.當想要對程序數據進行控制和描述時,維護一個結構.結構的數據類型設計,和讀代碼時一樣,不用一次到位,一邊寫代碼一邊根據需要增加(筆者在前面數據類設計中提到過,即使有冗余屬性問題也不大---也就是代碼不夠優雅).結構的好處是他是全局變量,可以動態修改,實時更新.

? ? ? ? 2.select函數的第一個參數,從前面的硬編碼listenfd+1變成了maxfd+1,實時更新.

? ? ? ? 3.遺憾本書并沒有把select講得很透徹,需要找資料補充.select的使用限于"復制粘貼".比如select調用到什么情況下結束?和時間長短是否有關系(像進程一樣由時間片停止)

小結

????????基于I/O多路復用的并發事件驅動服務器的一點理解

? ? ? ? ? ??

????????

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

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

相關文章

系統可靠性分析:指標解析與模型應用全覽

以下是關于系統可靠性分析中可靠性指標、串聯系統與并聯系統、混合系統、系統可靠性模型的相關內容&#xff1a; 一、可靠性指標 可靠度&#xff1a;是系統、設備或元件在規定條件和規定時間內完成規定功能的概率。假設一個系統由多個部件組成&#xff0c;每個部件都有其自身…

數字高程模型(DEM)公開數據集介紹與下載指南

數字高程模型&#xff08;DEM&#xff09;公開數據集介紹與下載指南 數字高程模型&#xff08;Digital Elevation Model, DEM&#xff09;廣泛應用于地理信息系統&#xff08;GIS&#xff09;、水文模擬、城市規劃、環境分析、災害評估等領域。本文系統梳理了主流的DEM公開數據…

Python+大模型 day01

Python基礎 計算機系統組成 基礎語法 如:student_num 4.標識符要做到見名知意,增強代碼的可讀性 關鍵字 系統或者Python定義的,有特殊功能的字符組合 在學習過程中,文件名沒有遵循標識符命名規則,是為了按序號編寫文件方便查找復習 但是,在開發中,所有的Python文件名稱必須…

C++引用編程練習

#include <iostream> using namespace std; double vals[] {10.1, 12.6, 33.1, 24.1, 50.0}; double& setValues(int i) { double& ref vals[i]; return ref; // 返回第 i 個元素的引用&#xff0c;ref 是一個引用變量&#xff0c;ref 引用 vals[i] } // 要調用…

機密虛擬機的威脅模型

本文將介紹近年興起的機密虛擬機&#xff08;Confidential Virtual Machine&#xff09;技術所旨在抵御的威脅模型&#xff0c;主要關注內存機密性&#xff08;confidentiality&#xff09;和內存完整性&#xff08;integrity&#xff09;兩個方面。在解釋該威脅可能造成的問題…

【Rust trait特質】如何在Rust中使用trait特質,全面解析與應用實戰

?? 歡迎大家來到景天科技苑?? &#x1f388;&#x1f388; 養成好習慣&#xff0c;先贊后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者簡介&#xff1a;景天科技苑 &#x1f3c6;《頭銜》&#xff1a;大廠架構師&#xff0c;華為云開發者社區專家博主&#xff0c;…

Simulink模型回調

Simulink 模型回調函數是一種特殊的 MATLAB 函數&#xff0c;可在模型生命周期的特定階段自動執行。它們允許用戶自定義模型行為、執行初始化任務、驗證參數或記錄數據。以下是各回調函數的詳細說明&#xff1a; 1. PreLoadFcn 觸發時機&#xff1a;Simulink 模型加載到內存之…

FPGA:Xilinx Kintex 7實現DDR3 SDRAM讀寫

在Xilinx Kintex 7系列FPGA上實現對DDR3 SDRAM的讀寫&#xff0c;主要依賴Xilinx提供的Memory Interface Generator (MIG) IP核&#xff0c;結合Vivado設計流程。以下是詳細步驟和關鍵點&#xff1a; 1. 準備工作 硬件需求&#xff1a; Kintex-7 FPGA&#xff08;如XC7K325T&…

Python爬蟲實戰:研究進制流數據,實現逆向解密

1. 引言 1.1 研究背景與意義 在現代網絡環境中,數據加密已成為保護信息安全的重要手段。許多網站和應用通過二進制流數據傳輸敏感信息,如視頻、金融交易數據等。這些數據通常經過復雜的加密算法處理,直接分析難度較大。逆向工程進制流數據不僅有助于合法的數據獲取與分析,…

Java Spring Boot項目目錄規范示例

以下是一個典型的 Java Spring Boot 項目目錄結構規范示例&#xff0c;結合了分層架構和模塊化設計的最佳實踐&#xff1a; text 復制 下載 src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── myapp/ │…

圖像顏色理論與數據挖掘應用的全景解析

文章目錄 一、圖像顏色系統的理論基礎1.1 圖像數字化的本質邏輯1.2 顏色空間的數學框架1.3 量化過程的技術原理 二、主要顏色空間的深度解析2.1 RGB顏色空間的加法原理2.2 HSV顏色空間的感知模型2.3 CMYK顏色空間的減色原理 三、圖像幾何屬性與高級特征3.1 分辨率與像素密度的關…

mysql兩張關聯表批量更新一張表存在數據,而另一張表不存在數據的sql

一、mysql兩張關聯表批量更新一張表存在、另一張表不存在的數據 創建user和user_order表 CREATE TABLE user (id varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,id_card varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NU…

PNG轉ico圖標(支持圓角矩形/方形+透明背景)Python腳本 - 隨筆

摘要 在網站開發或應用程序設計中&#xff0c;常需將高品質PNG圖像轉換為ICO格式圖標。本文提供一份基于Pillow庫實現的&#xff0c;能夠完美保留透明背景且支持導出圓角矩形/方形圖標的格式轉換腳本。 源碼示例 圓角方形 from PIL import Image, ImageDraw, ImageOpsdef c…

在線SQL轉ER圖工具

在線SQL轉ER圖網站 在數據庫設計、軟件開發或學術研究中&#xff0c;ER圖&#xff08;實體-關系圖&#xff09; 是展示數據庫結構的重要工具。然而&#xff0c;手動繪制ER圖不僅耗時費力&#xff0c;還容易出錯。今天&#xff0c;我將為大家推薦一款非常實用的在線工具——SQL…

繪制時間對應的數據曲線

頭文件#pragma once #include "ChartControl.h" #include <vector> #include "DBOperate.h&

【挑戰項目】 --- 微服務編程測評系統(在線OJ系統)(二)

三十二、Swagger介紹&使用 官網:https://swagger.io/ 什么是swagger Swagger是一個接口文檔生成工具,它可以幫助開發者自動生成接口文檔。當項目的接口發生變更時,Swagger可以實時更新文檔,確保文檔的準確性和時效性。Swagger還內置了測試功能,開發者可以直接在文檔中…

人事管理系統總結

1.Maven 創建 Spring Boot 項目&#xff1a; 主要使用 Maven 創建 Spring Boot 項目、配置 MySQL 數據庫、回顧 Spring Boot 分層架構、使用 MyBatis 逆向工程生成代碼及整合測試項目等內容&#xff0c;具體如下&#xff1a; Maven 創建 Spring Boot 項目 可通過 IDEA 直接創…

SpringBoot--springboot簡述及快速入門

spring Boot是spring提供的一個子項目&#xff0c;用于快速構建spring應用程序 傳統方式&#xff1a; 在眾多子項目中&#xff0c;spring framework項目為核心子項目&#xff0c;提供了核心的功能&#xff0c;其他的子項目都需要依賴于spring framework&#xff0c;在我們實際…

INT202 Complexity of Algroithms 算法的復雜度 Pt.7 NP-Completeness NP完全性

文章目錄 1.P與NP問題1.1 計算上難以解決的問題&#xff08;Hard Computational Problems&#xff09;1.2 決策問題和優化問題&#xff08;Decision/Optimization problems&#xff09;1.3 計算問題的正式定義1.4 復雜性類1.4.1 復雜性類 P P P1.4.2 證明&#xff08;Certifica…

websocketpp 安裝及使用

介紹 WebSocket 是從 HTML5 開始支持的一種網頁端和服務端保持長連接的消息推送機制。 傳統的 web 程序都是屬于 "一問一答" 的形式&#xff0c;即客戶端給服務器發送了一個 HTTP 請求&#xff0c;服務器給客戶端返回一個 HTTP 響應。這種情況下服務器是屬于被動…