Linux環(huán)境下高并發(fā)web服務(wù)器 的設(shè)計(jì)與實(shí)現(xiàn).docx
Linux環(huán)境下高并發(fā)web服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)摘要隨著信息技術(shù)的飛速開(kāi)展,互聯(lián)網(wǎng)已經(jīng)成為社會(huì)生產(chǎn)生活中不可缺少的一局部。特別是近十年來(lái),由于移動(dòng)技 術(shù)的進(jìn)步和智能移動(dòng)設(shè)備的普及,互聯(lián)網(wǎng)用戶數(shù)量呈爆發(fā)式增長(zhǎng),越來(lái)越多的行業(yè)正在通過(guò)互聯(lián)網(wǎng)進(jìn)行變革。用戶 群體的開(kāi)展改變了互聯(lián)網(wǎng)服務(wù)的形式,越來(lái)越多的服務(wù)器需要同時(shí)為大量客戶提供服務(wù)。因此,如何設(shè)計(jì)服務(wù)器的 通信框架,如何有效利用服務(wù)器的系統(tǒng)資源,成為服務(wù)器開(kāi)發(fā)人員關(guān)注的焦點(diǎn)。Web應(yīng)用具有連接間隔短、突發(fā)性強(qiáng)、響應(yīng)時(shí)間短等特點(diǎn),它是一種對(duì)并發(fā)性要求很高的服務(wù)。本文在服務(wù)器系 統(tǒng)中選擇主流的Linux操作系統(tǒng),采用C+,結(jié)合Socket、I/O多路復(fù)用技術(shù)epoll、無(wú)阻塞I/O、線程池、定時(shí)器和 Reactor事件處理模式,設(shè)計(jì)并實(shí)現(xiàn)了一個(gè)穩(wěn)定支持高并發(fā)的Web服務(wù)器。本文首先介紹和分析了Wob服務(wù)器的相關(guān)技術(shù),包括Socket、epolK Reactor事件處理模式、線程池和數(shù)據(jù)庫(kù)連 接池;重點(diǎn)討論了epoll與其他I/O模型的區(qū)別,以及epoll模型的特點(diǎn)。其次,根據(jù)Reactor模式分析了服務(wù)器的整圖3. 4事件處理器與存儲(chǔ)隊(duì)列存儲(chǔ)單元從阻塞隊(duì)列獲取獲取數(shù) 據(jù)進(jìn)行存儲(chǔ)。如圖3. 5所示。圖3. 5存儲(chǔ)隊(duì)列與存儲(chǔ)單元3. 2事件別離器流程事件別離器主要負(fù)責(zé)接收新連接、偵聽(tīng)到達(dá)事件。HTTP長(zhǎng)連接可以減少TCP連接的創(chuàng)立次數(shù),使客戶端和服務(wù)器能 夠有效復(fù)用TCP連接。但是,“在長(zhǎng)連接應(yīng)用中,服務(wù)器與客戶端實(shí)例都保持一個(gè)持久的連接,這將大量消耗服務(wù)器資源,特別是在一些大型應(yīng)用系統(tǒng)中更是如 此,大量并發(fā)的長(zhǎng)連接有可能導(dǎo)致新的請(qǐng)求被阻塞甚至系統(tǒng)崩潰18?!睘榱藢?duì)長(zhǎng)連接進(jìn)行管控,服務(wù)器可以通過(guò)實(shí)現(xiàn)定時(shí)器,對(duì)每個(gè)連接記錄超時(shí)時(shí)間點(diǎn)來(lái)解決這個(gè)問(wèn)題。每當(dāng)某個(gè) 連接有新請(qǐng)求到達(dá)時(shí)重置該連接的定時(shí)器,如果連接超時(shí)那么服務(wù)器主動(dòng)釋放連接。判斷超時(shí)和重置定時(shí)器的工作均 由事件別離器完成,事件別離器工作流程如圖3. 6所示。設(shè)置新連接的定時(shí) 器,把新邇接加入設(shè)置新連接的定時(shí) 器,把新邇接加入重置龍?jiān)亩〞r(shí)器,把 事件和處理方法加入到I 到檢測(cè)集合中 II 事件阻塞隊(duì)列中 I圖3.6事件別離器流程3. 3事件處理器流程事件處理器是服務(wù)器的核心模塊,主要負(fù)責(zé)的工作是:服務(wù)器的I/O操作、業(yè)務(wù)處理,因此對(duì)服務(wù)器的業(yè)務(wù)拓展 工作主要是對(duì)事件處理器的功能進(jìn)行拓展。在本工程實(shí)現(xiàn)的Web服務(wù)器中,I/O操作主要是指對(duì)Socket進(jìn)行讀寫(xiě)操 作 ,業(yè)務(wù)處理主要是指對(duì)接收到的HTTP請(qǐng)求報(bào)文進(jìn)行解析,并生成相應(yīng)的HTTP響應(yīng)報(bào)文。同時(shí)為了能夠支持用戶登錄 功能和用戶注冊(cè)功能,當(dāng)HTTP請(qǐng)求為該兩種功能請(qǐng)求時(shí),事件處理器還需要通過(guò)訪問(wèn)數(shù)據(jù)庫(kù)對(duì)接收到的用戶名和用 戶密碼進(jìn)行判斷或存儲(chǔ)操作。事件處理器的整體流程如圖3. 7所示。圖3. 7事件處理器流程在本工程中事件處理器的業(yè)務(wù)處理可以分為兩個(gè)模塊:HTTP請(qǐng)求報(bào)文解析模塊、HTTP 響應(yīng)報(bào)文生成模塊。3. 3. 1 HTTP請(qǐng)求報(bào)文解析模塊本模塊主要工作是對(duì)客戶端發(fā)送來(lái)的HTTP請(qǐng)求報(bào)文進(jìn)行解析。HTTP請(qǐng)求報(bào)文由請(qǐng)求行、請(qǐng)求頭部、空白行、請(qǐng) 求體構(gòu)成,每一行都以CRLF (回車(chē)符和換行符)作為結(jié)尾標(biāo)志19。在IITTP/L1中,請(qǐng)求行由請(qǐng)求方法、URI、HTTP協(xié)議版本構(gòu)成。請(qǐng)求頭部由多行構(gòu)成,每行以鍵值對(duì)的形式表示 (鍵為頭部字段名)。請(qǐng)求頭部包含了一些該連接和報(bào)文的信息,如表示長(zhǎng)連接狀態(tài)的keep-alive、請(qǐng)求體的編碼 方式content-type等??瞻仔袥](méi)有數(shù)據(jù)只有CRLF表示空白的一行,用來(lái)區(qū)分請(qǐng)求頭部和請(qǐng)求體。請(qǐng)求體攜帶客戶端 發(fā)送的數(shù)據(jù),如通過(guò)POST請(qǐng)求報(bào)文發(fā)送的表單。HTTP請(qǐng)求解析模塊主要有三個(gè)狀態(tài):解析請(qǐng)求行、解析請(qǐng)求頭部、解析請(qǐng)求體。狀態(tài)轉(zhuǎn)移如圖3. 8所示。GET請(qǐng)求報(bào) 文和POST請(qǐng)求報(bào)文是本文的主要解析對(duì)象。GET請(qǐng)求報(bào)文把參數(shù)存放在URL請(qǐng)求體數(shù)據(jù)為空,事件處理器無(wú)需解析GET請(qǐng)求報(bào)文的請(qǐng)求體。POST請(qǐng)求報(bào)文的參數(shù)被存放在POST請(qǐng)求報(bào)文的請(qǐng)求體中,事件處理器需要對(duì) POST請(qǐng)求報(bào)文的請(qǐng)求體進(jìn)行解析,從中獲取報(bào)文參數(shù)。登陸和注冊(cè)通過(guò)POST報(bào)文發(fā)送請(qǐng)求,用戶名和用戶密碼存放在請(qǐng)求體中。在解析請(qǐng)求體過(guò)程中,需要對(duì)通過(guò)解 析得到的用戶名、用戶密碼進(jìn)行處理:當(dāng)報(bào)文請(qǐng)求為登錄時(shí),向存儲(chǔ)單元查詢用戶名、用戶密碼進(jìn)行校驗(yàn);當(dāng)報(bào)文 請(qǐng)求為注冊(cè)時(shí),向存儲(chǔ)單元查詢用戶名、密碼合法性,如果合法那么進(jìn)行存儲(chǔ)。3.3.2 HTTP響應(yīng)報(bào)文生成模塊 本模塊主要工作是生成發(fā)送給客戶端的HTTP響應(yīng)報(bào)文。HTTP響應(yīng)報(bào)文由響應(yīng)行、響應(yīng) 頭部、空白行、響應(yīng)體構(gòu)成,每一行以CRLF表示該行結(jié)尾。響應(yīng)行由HTTP協(xié)議 版本、狀態(tài)碼、狀態(tài)碼描述構(gòu)成。狀態(tài)碼由三個(gè)十進(jìn)制數(shù)字組成,狀態(tài)碼的類(lèi)型由第一個(gè)數(shù)字定義。狀態(tài)碼和狀態(tài)碼描述表示HTTP響應(yīng)報(bào)文的報(bào) 文類(lèi)型。HTTP響應(yīng)報(bào)文生成模塊流程如圖3. 9所示。圖3. 8 HTTP解析模塊狀態(tài)轉(zhuǎn)移圖3. 9 HTTP響應(yīng)報(bào)文生成模塊流程“客戶端請(qǐng)求資源合法”是指客戶端請(qǐng)求的資源存在并且是一些指定的文件,而不是某個(gè)文件夾。3.4日志系統(tǒng)日志是記錄服務(wù)器運(yùn)行狀態(tài)的文件,對(duì)于服務(wù)器開(kāi)發(fā)人員和服務(wù)器運(yùn)維人員而言日志是一種能夠直觀地觀察服 務(wù)器狀態(tài)的重要文件。通過(guò)日志,服務(wù)器開(kāi)發(fā)人員可以查看服務(wù)器的日常運(yùn)行狀態(tài),對(duì)服務(wù)器架構(gòu)和功能作出調(diào)整 和拓展;服務(wù)器運(yùn)維人員可以根據(jù)日志中的錯(cuò)誤信息對(duì)服務(wù)器進(jìn)行錯(cuò)誤排查。日志系統(tǒng)的實(shí)現(xiàn)有兩種方式:同步模 式和異步模式。同步模式的寫(xiě)入操作與事件處理器串行執(zhí)行。寫(xiě)日志文件會(huì)涉及到I/O操作,同步模式在I/O操作時(shí)會(huì)阻塞整個(gè) 處理流程。當(dāng)單條日志記錄較大時(shí),事件處理器會(huì)被阻塞較長(zhǎng)時(shí)間,整個(gè)服務(wù)器的并發(fā)度將有所下降。如果服務(wù)器 需要處理大量連接請(qǐng)求時(shí),寫(xiě)日志操作可能會(huì)成為系統(tǒng)瓶頸。異步模式需要阻塞隊(duì)列作為事件處理器和寫(xiě)日志模塊的傳輸介質(zhì)。事件處理器把日志記錄存入阻塞隊(duì)列,寫(xiě)日 志模塊異步地從阻塞隊(duì)列中獲取日志記錄并寫(xiě)入日志文件。異步模式把寫(xiě)日志操作與業(yè)務(wù)處理流程進(jìn)行別離,防止 業(yè)務(wù)處理流程被阻塞,提高了服務(wù)器業(yè)務(wù)處理的并發(fā)度。日志記錄根據(jù)記錄信息被劃分為多個(gè)等級(jí)。例如,日志記錄被分為調(diào)試信息、運(yùn)行信息、錯(cuò)誤信息等幾個(gè)級(jí)別 ,服務(wù)器正常運(yùn)行時(shí)僅記錄運(yùn)行信息和錯(cuò)誤信息;服務(wù)器調(diào)試時(shí)記錄包括調(diào)試信息的所有信息。服務(wù)器可以根據(jù) 不 同的運(yùn)行狀態(tài)選擇不同的日志等級(jí),過(guò)濾無(wú)需記錄的日志信息,從而提高日志文件的可讀性。日志系統(tǒng)的寫(xiě)入記錄 流程如圖3. 10所示。根據(jù)日志等 級(jí)、日志參數(shù) 創(chuàng)立相應(yīng)的E 志記錄 1 < JU)第N個(gè)日志文件結(jié)束同步璜式日阻先入業(yè)不11 志塞處板異步建式寫(xiě)日志模塊異步地從阻塞隊(duì)列中茨取日志記錄,并把日志記錄寫(xiě)入日志文件圖3.10寫(xiě)入日志記錄流程4工程實(shí)現(xiàn)4.1服務(wù)器整體功能 本工程是在Linux環(huán)境下使用C+實(shí)現(xiàn)的Web服務(wù)器。目標(biāo)服務(wù)器基于Reactor模式,結(jié)合了 epoll和非阻塞Socket,利用線程池和數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn)了LT模式、ET模式下對(duì)GET請(qǐng)求報(bào)文、POST請(qǐng)求報(bào)文的解析和響應(yīng),使用定 時(shí)器實(shí)現(xiàn)了對(duì)長(zhǎng)連接的管控。此外,本工程還實(shí)現(xiàn)了同步和異步兩種模式下的日志系統(tǒng),用于記錄系統(tǒng)運(yùn)行狀態(tài)。 4.2阻塞隊(duì)列STL向C+開(kāi)發(fā)者提供了deque、queue等模板類(lèi)隊(duì)列,這些模板類(lèi)使用方便、接口清晰,但不具備線程平安性。 根據(jù)參考文獻(xiàn)20的第十二條: library implementation that allows multiple readers on one container and multiple writers on separate containers. You can't hope for the library to eliminate the need for manual concurrency control, and you can,t rely on any thread support at all. ”可知如果要實(shí)現(xiàn)STL的線程平安性,程序員必須 自己去完成相關(guān)平安措施。本工程通過(guò)互斥鎖、條件變量對(duì)deque重新封裝,利用“生產(chǎn)者-消費(fèi)者”模式實(shí)現(xiàn)了具有線程平安性的阻塞隊(duì) 列。力口鎖(lock mutex)被條件兗量 consumer 阻塞元素出隊(duì)解鎖(unlock mutex)圖4.1阻塞隊(duì)列的入隊(duì)和出隊(duì)4.3日志系統(tǒng)4.3.1 單例模式為了防止日志文件混亂,日志系統(tǒng)在服務(wù)器運(yùn)行過(guò)程中應(yīng)該只存在一個(gè)實(shí)例,即單例模式實(shí)現(xiàn)日志 系統(tǒng)。單例模式是最常用的設(shè)計(jì)模式之一,通過(guò)私有化構(gòu)造函數(shù)來(lái)保證一個(gè)類(lèi)無(wú)法類(lèi)外實(shí)例化,并提供相應(yīng)的實(shí)例訪問(wèn)接口給 其它程序模塊訪問(wèn),該接口只能獲取該類(lèi)的唯一實(shí)例。在C+11標(biāo)準(zhǔn)21中,對(duì)局部靜態(tài)變量的初始化作出以下要 求:“Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined. n 因此,在C+11 標(biāo)準(zhǔn)中,局部靜態(tài)變量的初始化 是具備線程平安性的。單例類(lèi)可以通過(guò)在實(shí)例訪問(wèn)接口中定義該類(lèi)的局部靜態(tài)對(duì)象來(lái)定義唯一實(shí)例。這種方法是單例模式中的懶漢模式,因?yàn)镃+中的局部靜態(tài)對(duì)象只有在第一次訪 問(wèn)時(shí)才會(huì)被初始化。實(shí)例接口代碼如下所示。1 .Log* Log:Instance() . static Log minstance;2 . return &m_instance;.)4.3.2 日志級(jí)別日志系統(tǒng)提供四種日志級(jí)別,從低到高依次為:DEBUG、INFO、WARN、ERRORo低級(jí)別的記錄信息會(huì) 被日志系統(tǒng)的級(jí)別過(guò)濾。DEBUG:記錄調(diào)試信息,如請(qǐng)求資源信息、數(shù)據(jù)庫(kù)查詢信息等。該級(jí)別的信息用于記錄調(diào)試服務(wù)器時(shí)服務(wù)器的詳 細(xì)運(yùn)行過(guò)程,在服務(wù)器實(shí)際運(yùn)行時(shí)不使用。INFO:記錄服務(wù)器當(dāng)前狀態(tài),如當(dāng)前的執(zhí)行流程、接收信息、連接數(shù)量等。該級(jí)別的信息用于記錄服務(wù)器實(shí)際 運(yùn)行時(shí)的狀態(tài)。WARN:記錄警告信息,如服務(wù)器連接數(shù)已滿。該級(jí)別的信息表示服務(wù)器可能出現(xiàn)了異常情況。ERROR:記錄系統(tǒng)出 錯(cuò)信息,如服務(wù)器初始化出錯(cuò)、創(chuàng)立Socket出錯(cuò)、檢測(cè)到了未定義的事件等。該級(jí)別的信息用于記錄服務(wù)器的出錯(cuò)信息。日志系統(tǒng)定義了四個(gè)宏:“LOG_DEBUG”、“L0GJNF0"、“LOGJVARN”、“ LOG_ERROR”。其它程序通過(guò)調(diào)用這四個(gè)宏向日志系統(tǒng)傳輸日志信息。為了區(qū)分記錄級(jí)別,四個(gè)宏都通過(guò)調(diào)用“LOG_BASE”來(lái)進(jìn)行級(jí)別檢查,不同的 接口調(diào)用“LOG_BASE”時(shí)傳入不同的記錄等級(jí)參數(shù)?!癓OGBASE”的偽代碼如圖4. 2所示。4.3.3 分日期、分記錄數(shù)量創(chuàng)立日志文件日志記錄寫(xiě)入日志文件時(shí)日志系統(tǒng)對(duì)當(dāng)前翻開(kāi)的日志文件的日期、記錄數(shù)量進(jìn)行檢查,日志系統(tǒng)根據(jù)日期、記 錄數(shù)量對(duì)日志文件進(jìn)行分類(lèi)。如果當(dāng)前日期與日志系統(tǒng)翻開(kāi)日志文件的日期不一致,那么日志系統(tǒng)新建日志文件,日 志名稱(chēng)為當(dāng)前日期;如果當(dāng)前翻開(kāi)的日志文件的記錄數(shù)到達(dá)單個(gè)日志文件的最大記錄數(shù),那么日志系統(tǒng)將創(chuàng)立一個(gè)日志名稱(chēng)帶有當(dāng)前日期和計(jì)數(shù)后綴的新日志文件22 o檢查日志文件日期、記錄數(shù)量的偽代碼如圖4. 3所示。4.3.4 同步模式、異步模式日志系統(tǒng)的模式在服務(wù)器初始化中決定:阻塞隊(duì)列長(zhǎng)度等于零為同步模式,阻塞隊(duì)列長(zhǎng)度大于零為異步模式。日志 系統(tǒng)根據(jù)不同的記錄級(jí)別、日志信息生成相應(yīng)的日志記錄,并寫(xiě)入日志文件。同步模式中記錄寫(xiě)入日志文件的I/O操作與處理業(yè)務(wù)的工作線程串行執(zhí)行,會(huì)阻塞工作線程;異步模式創(chuàng)立一個(gè)日志寫(xiě)入線程,工作線程把日志 記錄插入阻塞隊(duì)列,由日志寫(xiě)入線程異步地從阻塞隊(duì)列獲取日志記錄并執(zhí)行I/O操作。、日志寫(xiě)入的偽代碼如圖4. 4 所示。Algorithm 1: LOG_BASEInput: level, loginfoif levelInstance.level thenWirteLog(level, loginfo);flush;end圖4.2 L0G_BASEAlgorithm 2: CheckLogif log. date * today or (count % maxCount) = 0 thenif log. date 盧 today thencreate new log, name is today;log. date = today;count = 1;elsecreate new log, name is today,(count / maxCount);endend圖4. 3檢查日志文件Algorithm 3: WriteLogInput: level, loginfoCheckLog;logging = C r eat eLogging (level. liglnfo);if is A sync thenLogging Q uque. p ush (logging);elsewrite (logging);end圖4. 4日志寫(xiě)入4.3.5 4線程池4. 4.1線程池成員線程池主要由兒個(gè)成員組成:存儲(chǔ)任務(wù)(任務(wù)為回調(diào)函數(shù))的阻塞隊(duì)列、負(fù)責(zé)線程互斥訪問(wèn)臨界 區(qū)的互斥鎖、負(fù)責(zé)線程同步的條件變量。4. 4.2工作線程的同步與競(jìng)爭(zhēng)根據(jù)圖3. 7可知線程池中的工作線程與主線程存在同步關(guān)系,與其它工作線程存在競(jìng)爭(zhēng)關(guān)系,即半同步/半異步模式。工作線程的執(zhí)行流程偽代碼如圖4. 5所示。Algorithm 4: Workmutex lock;while threadpool is not closed doif BlockQueue is not empty thenget task from BlockQueue;mutex unlock:processing the task;mutex lock;elsethread is blocked by condition variable;endendmutex unlock;圖4.5工作線程工作線程初始化后對(duì)線程池中的mutex進(jìn)行加鎖,然后訪問(wèn)臨界區(qū),在線程池關(guān)閉前循環(huán)執(zhí)行。如 果存儲(chǔ)任務(wù)的阻塞隊(duì)列不為空,工作線程從阻塞隊(duì)列中取出任務(wù),然后對(duì)mutex解鎖并處理任務(wù)。任務(wù)完成后重新嘗試對(duì)mutex力口 鎖,再次參與競(jìng)爭(zhēng)。如果存儲(chǔ)任務(wù)的阻塞隊(duì)列為空,工作線程被條件變量阻塞(工作線程被條件變量阻塞會(huì)釋放 mutex的所有權(quán),即解鎖),只有主線程向阻塞隊(duì)列插入新的任務(wù)或主線程關(guān)閉線程池時(shí)才被喚醒(工作線程被喚醒 后重新嘗試對(duì)mutex加鎖,重新參與競(jìng)爭(zhēng))。兩種喚醒方式的區(qū)別在于新的任務(wù)插入阻塞隊(duì)列只會(huì)喚醒一個(gè)被條件變 量阻塞的工作線程,線程池關(guān)閉會(huì)喚醒所有被條件變量阻塞的線程。4.5數(shù)據(jù)庫(kù)連接池 數(shù)據(jù)庫(kù)連接池的實(shí)現(xiàn)方法比線程池更簡(jiǎn)單,本質(zhì)是使用一個(gè)阻塞隊(duì)列存儲(chǔ)空閑的數(shù)據(jù)庫(kù)連接。工 作線程向數(shù)據(jù)庫(kù)連接池申請(qǐng)和歸還數(shù)據(jù)庫(kù)連接實(shí)際是對(duì)阻塞隊(duì)列的出隊(duì)和入隊(duì)操作。但阻塞隊(duì)列的入隊(duì)操作如果交給程序員處理 可能會(huì)存在遺漏入隊(duì)的情況,導(dǎo)致空閑的數(shù)據(jù)庫(kù)連接沒(méi)有重新進(jìn)池,從而浪費(fèi)空閑資源,甚至最后會(huì)導(dǎo)致數(shù)據(jù)庫(kù)連 接池?zé)o空閑的數(shù)據(jù)庫(kù)連接可用。同時(shí),程序沒(méi)有主動(dòng)釋放動(dòng)態(tài)申請(qǐng)的資源,造成了內(nèi)存泄漏。為了防止某個(gè)線程使用完數(shù)據(jù)庫(kù)連接后沒(méi)有釋放數(shù)據(jù)庫(kù)連接的所有權(quán),數(shù)據(jù)庫(kù)連接的分配和回收通常采用RAH (Resource Acquisition Is Initialization,資源獲取就是初始化)機(jī)制,程序通過(guò)定義一個(gè)封裝了從數(shù)據(jù)庫(kù)連 接池獲取和歸還連接的RAU類(lèi)來(lái)管理連接的分配和回收23。RAH類(lèi)在構(gòu)造函數(shù)中獲取數(shù)據(jù)庫(kù)連接,在析構(gòu)函數(shù)中 歸還數(shù)據(jù)庫(kù)連接。通過(guò)RAU機(jī)制,工作線程只能通過(guò)定義一個(gè)RAH實(shí)例獲取數(shù)據(jù)庫(kù)連接。同時(shí)工作線程無(wú)需主動(dòng)歸 還數(shù)據(jù)庫(kù)連接,因?yàn)榫€程對(duì)數(shù)據(jù)庫(kù)連接的所有權(quán)周期就是RAH實(shí)例的生命周期,當(dāng)線程完成數(shù)據(jù)庫(kù)訪問(wèn)后退出相應(yīng) 作用域,RAH實(shí)例被系統(tǒng)自動(dòng)銷(xiāo)毀,RAH實(shí)例的析構(gòu)函數(shù)釋放數(shù)據(jù)庫(kù)連接。數(shù)據(jù)庫(kù)連接RAH類(lèi)的構(gòu)造函數(shù)和析構(gòu)函 數(shù)的偽代碼如圖4. 6所示。Algorithm 5: Construct SqlPoolRAIIOutput: sqlConnectionget sqlConnection from sqlConnectionQueue;mySqlConnection = sqlConnection;Algorithm 6: Destruct SqlPoolRAIIif mySqlConnection is not empty thensqlConnectionQueue.push(mySqlConnection):end圖4.6數(shù)據(jù)庫(kù)連接RAH類(lèi)的構(gòu)造函數(shù)和析構(gòu)函數(shù)4. 6解析HTTP請(qǐng)求報(bào)文4. 6.1 HTTP請(qǐng)求報(bào)文解析流程根據(jù)圖3. 8可知HTTP解析主要分為三局部:解析請(qǐng)求行、解析請(qǐng)求頭部、解析請(qǐng)求體o請(qǐng)求行主要解析請(qǐng)求報(bào)文的請(qǐng)求方法、URI、HTTP協(xié)議版本,請(qǐng)求頭部主要解析關(guān)于連接和報(bào)文的各種信息,請(qǐng)求體主要解析某些報(bào)文的參數(shù)(POST報(bào)文)。解析請(qǐng)求體前逐行解析行、請(qǐng)求頭部。本工程HTTP請(qǐng)求報(bào)文解析模塊從HTTP請(qǐng)求中解析得到的信息,包含:請(qǐng)求方法,URL協(xié)議版本,連接類(lèi)型(Connection,表示短連接或長(zhǎng)連接),長(zhǎng)連接信息(keep-alive)請(qǐng)求體編碼方式,請(qǐng)求體長(zhǎng)度,表單參數(shù)(用 戶名、密碼)。4. 6. 2解析請(qǐng)求行請(qǐng)求行由請(qǐng)求方法、URI和HTTP協(xié)議版本組成,以空格分隔,整行格式為“請(qǐng)求方法URI HTTP/協(xié)議版本”。請(qǐng) 求行可以通過(guò)正那么表達(dá)式進(jìn)行匹配。由于請(qǐng)求行的三個(gè)元素由空格隔開(kāi),并且版本協(xié)議前帶有“HTTP/",所以匹配 正那么表達(dá)式為:乂廠*)(廠*) HTTP/(1*)$通過(guò)正那么表達(dá)式匹配可得到請(qǐng)求報(bào)文的請(qǐng)求方法、URI和HTTP協(xié)議版本。URI作為 唯一資源標(biāo)識(shí)符,本工程可以通過(guò)URI和自定義的“URI-資源路徑”映射表得知請(qǐng)求資源的路徑。4. 6. 3解析請(qǐng)求頭部請(qǐng)求頭部包含許多連接信息,以鍵值對(duì)的形式表示,每個(gè)鍵值對(duì)占一行。STL提供了以鍵值對(duì)形式存儲(chǔ)的模板 類(lèi):map、unordered_mapo其中map底層由紅黑樹(shù)實(shí)現(xiàn),unorderedjnap底層由哈希表實(shí)現(xiàn)。由于HTTP請(qǐng)求頭部中的 信息無(wú)順序意義,因此本工程使用時(shí)間復(fù)雜度更低的unorderecUnap存儲(chǔ)請(qǐng)求頭部信息。請(qǐng)求頭部中的鍵值對(duì)以冒號(hào)和空格(“:”)進(jìn)行分割,因此可以使用正那么表達(dá)式對(duì)鍵值對(duì)進(jìn)行匹配。匹配請(qǐng) 求頭部信息的正那么表達(dá)式:”:*): ?(.*)$如果匹配失敗,說(shuō)明解析到了空白行,結(jié)束解析請(qǐng)求頭部。解析請(qǐng)求體請(qǐng)求體的長(zhǎng)度和編碼方式在解析請(qǐng)求首部中得知,鍵的名稱(chēng)分別為"Content-Length"和"Content-Type' o 本工程對(duì)編碼方式為uapplication/x-www-form-(JRIencodeclv (大多數(shù)主流瀏覽器提交表單的默認(rèn)編碼方式)的 POST請(qǐng)求進(jìn)行解析?!癮pplication/x-www-form-URIencoded”的數(shù)據(jù)參數(shù)是鍵值對(duì),表現(xiàn)形式為“key=value”,因此可以使用 unorderedjnap存儲(chǔ)鍵值對(duì)參數(shù)。多個(gè)參數(shù)之間由別離。編碼規(guī)那么為:參數(shù)中的空格使用“ + ”替換,非數(shù)字、 字母的特殊字符使用三個(gè)字符“%xy”替換,其中“xy”表示該字符的十六進(jìn)制表示形式。請(qǐng)求體的整體解析過(guò)程:根據(jù)"app 1 i cat i on/x-w wf orm-UR I encoded v編碼方式對(duì)請(qǐng)求體進(jìn)行反編碼,別離鍵 值對(duì)參數(shù)并存入哈希表中。判斷請(qǐng)求報(bào)文是否請(qǐng)求注冊(cè)或登錄,如果是那么根據(jù)相應(yīng)的參數(shù)判斷請(qǐng)求是否合法,如參 數(shù)中否含有用戶名、用戶密碼。本工程的登陸與注冊(cè)校驗(yàn)過(guò)程由HTTP解析模塊完成。客戶端通過(guò)POST請(qǐng)求報(bào)文提交表單,用戶名和用戶密碼存 放在請(qǐng)求體中。服務(wù)器解析post請(qǐng)求消息并獲取用戶名和密碼,然后通過(guò)數(shù)據(jù)庫(kù)連接訪問(wèn)數(shù)據(jù)庫(kù),并查詢用戶名和 密碼是否合法。HTTP請(qǐng)求體解析過(guò)程如圖4. 7所示。Algorithm 7: Parse Postif method = POST and Content-Type =application/x-www-form-urlencoded thenEncoded (Body);if Register or Login thenif username and password are legal then path = welcome;elsepath = error;endendend圖4.7解析HTTP請(qǐng)求體 如果請(qǐng)求報(bào)文是登錄或注冊(cè)請(qǐng)求,那么返回給客戶端的資源的路徑由用戶名、用戶密碼檢查結(jié) 果決定:如果信息正確,資源路徑為成功頁(yè)面的路徑;如果信息錯(cuò)誤,那么資源路徑為錯(cuò)誤頁(yè)面的路徑。4. 7生成HTTP響應(yīng)報(bào)文4. 7.1 HTTP響應(yīng)報(bào)文生成流程響應(yīng)報(bào)文生成模塊根據(jù)解析模塊的結(jié)果,生成響應(yīng)行、響應(yīng)頭部、空白行和響應(yīng)體。 響應(yīng)行主耍生成狀態(tài)碼;響應(yīng)頭部主要生成長(zhǎng)連接狀態(tài)、響應(yīng)體長(zhǎng)度;響應(yīng)體為根據(jù)解析結(jié)果得到的資源文件。本工程的HTTP響應(yīng)報(bào)文生成 模塊中,因?yàn)槊總€(gè)連接的報(bào)文信息都可能各不相同,因此響應(yīng)行、響應(yīng)頭部、空白行存儲(chǔ)在各個(gè)連接的響應(yīng)報(bào)文緩沖區(qū)中。為了加快發(fā)送報(bào)文時(shí)對(duì)資源文件的讀取速率,響應(yīng)體對(duì)應(yīng)的資源文件通過(guò) 內(nèi)存映射存放到內(nèi)存中?!皟?nèi)存映射文件提供了一種獨(dú)特的內(nèi)存管理特征,它允許應(yīng)用程序與通過(guò)指針訪問(wèn)動(dòng)態(tài)內(nèi)存相同的方式訪問(wèn)磁盤(pán)上的文件。因 此,可以在進(jìn)程地址空間中將磁盤(pán)上的文件局部或者全部映射到特定地址范圍,然后通過(guò)指針就可以訪問(wèn)內(nèi)存映射 文件中的內(nèi)容。一旦該文件被映射,就可以訪問(wèn)它,就像整個(gè)文件已經(jīng)加載內(nèi)存一樣,從而可以不必對(duì)文件執(zhí)行I/O 操作,這對(duì)大數(shù)據(jù)量文件來(lái)說(shuō)存取效率較高24?!眻D4. 8響應(yīng)報(bào)文存儲(chǔ)關(guān)系4.7. 2生成狀態(tài)碼根據(jù)圖3. 9可知,能夠成功請(qǐng)求資源的請(qǐng)求報(bào)文需要經(jīng)過(guò)三次檢查:成功解析請(qǐng)求報(bào)文、客戶端請(qǐng)求的資源合 法、客戶端擁有足夠權(quán)限訪問(wèn)資源。每個(gè)階段出錯(cuò)都會(huì)生成相應(yīng)的狀態(tài)碼,只有三次檢查都通過(guò)才會(huì)生成表示成功 體框架,包括框架中的事件別離器、事件處理器;其中事件處理器是核心模塊,重點(diǎn)分析了其HTTP請(qǐng)求報(bào)文解析模 塊和HTTP響應(yīng)報(bào)文生成模塊;還分析了日志系統(tǒng)的同步模式和異步模式。在完成需求分析后,對(duì)服務(wù)器的各個(gè)模塊 進(jìn)行設(shè)計(jì)和實(shí)現(xiàn),包括阻塞隊(duì)列、日志系統(tǒng)、線程池、數(shù)據(jù)庫(kù)連接池、HTTP請(qǐng)求報(bào)文解析、HTTP響應(yīng)報(bào)文生成以及 管控HTTP長(zhǎng)連接的定時(shí)器。各模塊通過(guò)面向?qū)ο蟮乃枷雽?shí)現(xiàn)了相應(yīng)的功能接口,降低了模塊間的耦合度。最后,本 文對(duì)服務(wù)器進(jìn)行了壓力測(cè)試和穩(wěn)定性測(cè)試,并對(duì)應(yīng)用層面的注冊(cè)功能、登錄功能和大文件傳輸功能進(jìn)行了測(cè)試。本 文涉及了Socket的監(jiān)聽(tīng)與連接、網(wǎng)絡(luò)I/O管理、線程池設(shè)計(jì)和HTTP協(xié)議分析,對(duì)解決Web服務(wù)器中遇到的問(wèn)題具有很 好的工程參考價(jià)值。關(guān)鍵詞:Linux, C+,高并發(fā),epoll, Reactor AbstractWith the rapid development of information technology, the Internet has become an indispensable part of social production and life. Especially in the past decade, due to the progress of mobile technology and the popularity of intelligent mobile devices, the number of Internet users is growing explosively, and more and more industries are changing through the Internet. The development of user groups has changed the form of Internet services, more and more servers need to provide services for a large number of customers at the same time. Therefore, how to design the communication framework of the server and how to effectively use the system resources of the server have become the focus of server developers.Web application has the characteristics of short connection interval, strong burst and short response time. It is a service with high concurrency requirements. In this thesis, we choose the mainstream Linux operating system in the server system, use C+, combine socket, I/O multiplexing technology epoll, non blocking I/O, thread pool, timer and Reactor event processing mode, design and implement a stable and high concurrent web server.This thesis first introduces and analyzes the related technologies of web server, including socket, epoll, Reactor event processing mode, thread pool and database connection pool; the differences between epoll and other I/O models and the characteristics of epoll model are discussed. Secondly, according to the Reactor mode, the overall framework of the server is analyzed, including the event separator and event processor in the framework; the event processor is the core module, focusing on the analysis of its HTTP request message parsing module and HTTP response message generation module; the synchronous mode and asynchronous mode of the log system are also analyzed. After the completion of the requirements analysis, the design and implementation of each module of the server, including blocking queue, log system, thread pool, database connection pool, HTTP request message parsing, HTTP response message generation and the timer to control the HTTP long connection. Each module realizes the corresponding function interface through the idea of object-oriented, which reduces the coupling degree between modules. Finally, this thesis tests the pressure and stability of the server, and tests the registration function, login function and large file transfer function of the application level. This thesis involves socket monitoring and connection, network I/O management, thread pool design and HTTP protocol analysis, which has good engineering reference value to solve the problems encountered in web server. Key words: Linux, C+, high-concurrency, epoll, Reactor目錄1緒論.12開(kāi)發(fā)技術(shù)介紹 22. 1 Socket,22.2 I/O多路復(fù)用技術(shù)EPOLL.41. 2.1 五種 I/O 模型 .42. 2 EPOLL42. 3 Reactor事件處理模式.7的狀態(tài)碼“200”。能否成功解析請(qǐng)求報(bào)文是由請(qǐng)求報(bào)文解析模塊進(jìn)行判斷的。如果HTTP請(qǐng)求報(bào)文格式出錯(cuò)(如請(qǐng) 求行格式出錯(cuò)),那么狀態(tài)碼設(shè)置為“400”。該階段檢查的“出錯(cuò)”僅表示請(qǐng)求報(bào)文格式出錯(cuò),而登錄或注冊(cè)請(qǐng)求中的用戶信息 出錯(cuò)不屬于該階段的檢查范圍,僅屬于應(yīng)用層面上的出錯(cuò)。所以用戶信息錯(cuò)誤的登錄或注冊(cè)請(qǐng)求也是一次成功的請(qǐng) 求,服務(wù)器發(fā)送的響應(yīng)報(bào)文依然是狀態(tài)碼為“200”的成功響應(yīng)報(bào)文,只是頁(yè)面資源是表示用戶信息出錯(cuò)的頁(yè)面,而 不是成功頁(yè)面??蛻舳苏?qǐng)求資源合法表示客戶端請(qǐng)求的資源應(yīng)該存在并且是有效資源,不能是某個(gè)文件夾??蛻舳藫碛凶銐驒?quán)限訪 問(wèn)資源表示客戶端請(qǐng)求的資源在服務(wù)器的權(quán)限是中是“其它用戶可讀"。Linux中的文件權(quán)限分為“可讀”、“可寫(xiě)”、“可執(zhí)行”,本工程主要檢查客戶端是否有權(quán)限讀資源,在開(kāi)發(fā)中使用SJR0TH (表 示其他用戶可讀的權(quán)限值,與文件的權(quán)限值進(jìn)行與運(yùn)算可知文件能否被其他用戶讀)對(duì)資源文件的權(quán)限進(jìn)行檢查。 生成狀態(tài)碼的偽代碼如圖4. 9所示。Algorithm 8: CreateStatusCode Output: Status Code if Parse Post = FALSE thenStatus Code = 400;endelse if resource does not exist or resource is a folder thenStatus Code = 404;endelse if resource is not readable thenStatus Code = 403;endelseStatus Code = 200;end圖4.9生成狀態(tài)碼的偽代碼生成響應(yīng)行、響應(yīng)頭部、空白行本工程定義了 “狀態(tài)碼-狀態(tài)碼描述”映射表,生成響應(yīng)行時(shí)向HTTP響應(yīng)報(bào)文緩沖區(qū)寫(xiě)入?yún)f(xié)議版本、狀態(tài)碼、狀 態(tài)條件。本工程定義了 “文件類(lèi)型-MIME類(lèi)型”映射表,生成響應(yīng)頭部時(shí)根據(jù)資源的文件類(lèi)型向HTTP響應(yīng)報(bào)文緩沖區(qū)寫(xiě)入 資源的MIME類(lèi)型參數(shù)(Content-Type) o同時(shí),根據(jù)連接類(lèi)型向緩沖區(qū)寫(xiě)入連接類(lèi)型參數(shù)(Connection),如果連 接類(lèi)型為長(zhǎng)連接還需寫(xiě)入長(zhǎng)連接參數(shù)(keep-alive) o長(zhǎng)連接類(lèi)型參數(shù)的值為timeout和max,表示連接生存時(shí)間和 最大請(qǐng)求數(shù)。最后寫(xiě)入響應(yīng)體長(zhǎng)度參數(shù)(Content-Length)和空白行。4. 7.4生成響應(yīng)體目標(biāo)資源文件通過(guò)內(nèi)存映射被映射到內(nèi)存中。服務(wù)器向客戶端發(fā)送響應(yīng)報(bào)時(shí)文從映射對(duì)象中讀取 數(shù)據(jù)并寫(xiě)入Socketo為了防止程序影響原文件,內(nèi)存映射類(lèi)型應(yīng)設(shè)為MAP_PRIVATE。這種類(lèi)型表示程序?qū)?nèi)存映射中的映射區(qū)進(jìn) 行修改時(shí)會(huì)執(zhí)行“寫(xiě)時(shí)拷貝”獲得一份私有的文件拷貝,對(duì)文件的修改都是對(duì)這篇私有內(nèi)存的修改,不寫(xiě)回原文件O4. 8定時(shí)器本工程通過(guò)定時(shí)器對(duì)HTTP長(zhǎng)連接進(jìn)行管控。服務(wù)器在初始化時(shí)定義連接的生存時(shí)間,接收到請(qǐng)求報(bào)文后為連接 設(shè)置定時(shí)器。定時(shí)器使用小頂堆實(shí)現(xiàn),每個(gè)節(jié)點(diǎn)存儲(chǔ)某個(gè)連接的定時(shí)器信息。定時(shí)器信息包括Socket的文件描述符、超時(shí)時(shí) 間點(diǎn)、回調(diào)函數(shù),其中超時(shí)時(shí)間點(diǎn)為定時(shí)器設(shè)置時(shí)間加上連接的生存時(shí)間,回調(diào)函數(shù)為關(guān)閉連接函數(shù)。各個(gè)信息的 作用是:主線程設(shè)置或重置連接的定時(shí)器時(shí)根據(jù)Socket的文件描述符找到指定的定時(shí)器節(jié)點(diǎn);主線程根據(jù)定時(shí)器的 超時(shí)時(shí)間點(diǎn)判斷該連接是否超時(shí),如果超時(shí)那么調(diào)用回調(diào)函數(shù)關(guān)閉連接。小頂堆的底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,根據(jù)節(jié)點(diǎn)的超時(shí)時(shí)間點(diǎn)排序建堆。主線程在重置定時(shí)器時(shí)需要根據(jù)文件描述符 找到定時(shí)器節(jié)點(diǎn),因此還需要定義一個(gè)“文件描述符-節(jié)點(diǎn)下標(biāo)”映射表,可以使用unorderedjnap實(shí)現(xiàn)。新增連接時(shí)判斷堆中是否存在含有該Socket文件描述符的節(jié)點(diǎn)。如果不存在,主線程向堆尾中插入新的定時(shí)器 節(jié)點(diǎn),并根據(jù)超時(shí)時(shí)間點(diǎn)對(duì)節(jié)點(diǎn)向上調(diào)整;如果存在,說(shuō)明之前使用該文件描述符的連接雖然已經(jīng)被關(guān)閉但目前事 件還到達(dá)該連接的超時(shí)時(shí)間點(diǎn),主線程重置該節(jié)點(diǎn)的超時(shí)時(shí)間點(diǎn),并對(duì)節(jié)點(diǎn)向下調(diào)整。某個(gè)連接有新的事件到達(dá),主線程重置該連接定時(shí)器的超時(shí)時(shí)間點(diǎn):通過(guò)文件描述符和“文件描述符-節(jié)點(diǎn)下 標(biāo)”的映射表找到定時(shí)器節(jié)點(diǎn)的下標(biāo),修改定時(shí)器節(jié)點(diǎn)的超時(shí)時(shí)間點(diǎn)并對(duì)節(jié)點(diǎn)向下調(diào)整。調(diào)整過(guò)程中定時(shí)器需要維護(hù)“文件描述符-節(jié)點(diǎn)下標(biāo)”的映射表。向上調(diào)整如圖4. 10所示,向下調(diào)整如圖4. 11所/Js o圖4.10定時(shí)器節(jié)點(diǎn)向上調(diào)整國(guó)弱陸禁漁IIR延您腐圖4.11定時(shí)器節(jié)點(diǎn)向下調(diào)整清除超時(shí)節(jié)點(diǎn)只需要判斷根節(jié)點(diǎn)是否超時(shí),如果超時(shí)那么刪除根節(jié)點(diǎn),調(diào)整堆:交換根 節(jié)點(diǎn)與最后一個(gè)節(jié)點(diǎn),刪除最后節(jié)點(diǎn)并對(duì)新的根節(jié)點(diǎn)向下調(diào)整。主線程不斷清除直到根節(jié)點(diǎn)不超時(shí)或堆為空。對(duì)于連接已經(jīng)關(guān)閉的節(jié)點(diǎn)無(wú)需 管理。因?yàn)槿绻行碌倪B接使用該節(jié)點(diǎn)的文件描述符,該節(jié)點(diǎn)會(huì)析構(gòu)舊連接的信息,存儲(chǔ)新連接的信息,并調(diào)整節(jié) 點(diǎn)位置;如果時(shí)間到達(dá)了舊連接的超時(shí)時(shí)間點(diǎn),該節(jié)點(diǎn)會(huì)與其它超時(shí)節(jié)點(diǎn)一起被清除。為了能夠有效地對(duì)超時(shí)連接進(jìn)行關(guān)閉,當(dāng)堆不為空時(shí)主線程應(yīng)有限地等待到達(dá)事件,并且等待時(shí)間為定時(shí)器根 節(jié)點(diǎn)的超時(shí)時(shí)間點(diǎn)減去當(dāng)前時(shí)間。在此期間內(nèi)如果沒(méi)有事件到達(dá)那么根節(jié)點(diǎn)對(duì)應(yīng)的連接一定超時(shí),需要關(guān)閉。|清輻時(shí)節(jié)點(diǎn)|"葉e噩;鬻|-0Y1 斐斐二處是,重置定時(shí)弱|圖4. 12堆不為空時(shí)主線程有限等待4. 9服務(wù)器整體流程4. 9.1服務(wù)器初始化服務(wù)器啟動(dòng)階段需要初始化一些數(shù)據(jù):偵聽(tīng)端口號(hào)、epoll模式、連接生存時(shí)間、優(yōu)雅退出、 數(shù)據(jù)庫(kù)信息(數(shù)據(jù)庫(kù)用戶名、密碼、數(shù)據(jù)庫(kù)名、數(shù)據(jù)庫(kù)訪問(wèn)端口)、工作線程數(shù)量、數(shù)據(jù)庫(kù)連接數(shù)量、日志開(kāi)關(guān)、日志等級(jí)、日志模 式。偵聽(tīng)端口號(hào):客戶端根據(jù)服務(wù)器的IP地址和偵聽(tīng)端口號(hào)發(fā)起TCP連接,服務(wù)器通過(guò)偵聽(tīng)端口號(hào)接收客戶端請(qǐng)求。 epoll模式:決定服務(wù)器使用LT模式還是ET模式。連接生存時(shí)間:決定一個(gè)空閑的連接可以維持多長(zhǎng)時(shí)間。優(yōu)雅退出:決定服務(wù)器關(guān)閉連接時(shí)是否優(yōu)雅退出。數(shù)據(jù)庫(kù)信息:用于初始化數(shù)據(jù)庫(kù)連接。日志開(kāi)關(guān):決定服務(wù)器是 否使用日志系統(tǒng)。日志等級(jí):決定服務(wù)器翻開(kāi)的日志系統(tǒng) 的等級(jí)。日志模式:決定日志系統(tǒng)使用同步模式還是異步模式。服務(wù)器運(yùn)行主線程流程如圖4. 13所示。error圖4. 13主線程流程工作線程流程如圖4. 14所示。圖4. 14工作線程流程5服務(wù)器測(cè)試測(cè)試環(huán)境 服務(wù)器系統(tǒng):ubuntul8. 04服務(wù)器處理器內(nèi)核總數(shù):4服務(wù)器內(nèi)存:8GB5.1 測(cè)試工具本工程使用WebBench對(duì)服務(wù)器進(jìn)行壓力測(cè)試和穩(wěn) 定測(cè)試25。WebBench是VeriTest公司開(kāi)發(fā)的一款測(cè)試工具,其原理是通過(guò)父進(jìn)程fork多個(gè)子進(jìn)程,由子進(jìn)程對(duì)目標(biāo)URI發(fā)起 實(shí)際請(qǐng)求并記錄請(qǐng)求結(jié)果。子進(jìn)程把結(jié)果返回給父進(jìn)程,由父進(jìn)程整理和統(tǒng)計(jì)子進(jìn)程記錄的信息,反應(yīng)于用戶。用 戶能夠通過(guò)WebBench向目標(biāo)Web服務(wù)器發(fā)起一定數(shù)量的并發(fā)請(qǐng)求,并發(fā)連接數(shù)和持續(xù)時(shí)間可由用戶決定,但并發(fā)數(shù)量 不能超過(guò)三萬(wàn)。5.2 壓力測(cè)試和穩(wěn)定測(cè)試的服務(wù)器參數(shù)關(guān)閉方式:優(yōu) 雅退出。線程數(shù)量:6O日志系統(tǒng):關(guān) 閉。epoll模式:偵聽(tīng)Socket設(shè)為L(zhǎng)T模式,連接Socket分LT模式和ET模式進(jìn)行測(cè)試。5.3 壓力測(cè)試單次測(cè)試時(shí)長(zhǎng)為5秒,并發(fā)連接數(shù)從1000開(kāi)始,以2000為步長(zhǎng)進(jìn)行增長(zhǎng),直到服務(wù)器支持上萬(wàn)并發(fā)。LT模式、ET 模式各進(jìn)行十次測(cè)試,測(cè)試結(jié)果見(jiàn)附錄。結(jié)果平均值如表5.1、5.2所示。表5. 1 LT模式壓力測(cè)試并發(fā)連接數(shù)數(shù)據(jù)傳輸速率bytes/s成功次數(shù)每秒成功次數(shù)10005464886. 4202652.26754. 630004481209.4214422.67146.850004441323.4221291.77375. 970004556732229431. 57647. 390004461308.42273117586. 6110004292933.3222241.87407. 7表5. 2 ET模式壓力測(cè)試并發(fā)連接數(shù)數(shù)據(jù)傳輸速率bytes/s成功次數(shù)每秒成功次數(shù)10005368129.2199063. 8663530004447417. 8213078.57104. 750004364842. 2215823.27193. 770004424853. 2223747. 17457. 890004196370. 8215830.37193.9110004193782. 7218356.87278. 1從表中可知LT模式和ET模式均能支持上萬(wàn)并發(fā),并且每秒處理的連接請(qǐng)求數(shù)(qps)約為7000。5.4 穩(wěn)定測(cè)試測(cè)試時(shí)長(zhǎng)為10分鐘,并發(fā)連接數(shù)11000。對(duì)ET模式、LT模式各進(jìn)行3次測(cè)試,測(cè)試結(jié) 果如下。11000 clients, running 600 sec.Speed=452658 pages/min, -2733954 bytes/sec.Requests: 4496798 susceed, 29787 failed.圖5.1 LT模式第一次穩(wěn)定測(cè)試11000 clients, running 600 sec.Speed=458109 pages/min, -2694015 bytes/sec.Requests: 4551932 susceed, 29163 failed.圖5. 2 LT模式第二次穩(wěn)定測(cè)試11000 clients, running 600 sec.Speed=443065 pages/min, -2833884 bytes/sec.Requests: 4400922 susceed, 29737 failed.圖5. 3 LT模式第三次穩(wěn)定測(cè)試11000 clients, running 600 sec.Speed=415562 pages/min, -3129087 bytes/sec.Requests: 4126594 susceed, 29035 failed.圖5. 4 ET模式第一次穩(wěn)定測(cè)試11000 clients, running 600 sec.Speed=424722 pages/min, -3033192 bytes/sec.Requests: 4218901 susceed, 28322 failed.圖5. 5 ET模式第二次穩(wěn)定測(cè)試11000 clients, running 600 sec.Speed=422485 pages/min, -3066281 bytes/sec.Requests: 4196183 susceed, 28669 failed.圖5.6 ET模式第三次穩(wěn)定測(cè)試根據(jù)測(cè)試結(jié)果可知服務(wù)器能在處理上萬(wàn)并發(fā)連接的情況下保持服務(wù)器穩(wěn)定,每秒處理 的連接請(qǐng)求數(shù)和壓力測(cè)試結(jié)果一樣約為7000。測(cè)試結(jié)果中的每秒字節(jié)數(shù)傳輸速率為負(fù)是因?yàn)閿?shù)據(jù)過(guò)大造成了整型溢出。5.5 注冊(cè)、登錄功能測(cè)試用戶表初始為空。rrysql> select * from user;Empty set (0.00 sec)圖5.7用戶表初始內(nèi)容注冊(cè) 用戶。C O A Not secure192.168.3.1. * y :首頁(yè)圖5.8首頁(yè)圖5. 9注冊(cè)圖5.10注冊(cè)成功,進(jìn)入功能界面mysql> select * from user;+| username|password|+| 123456|123456|+1 row inset(0.00 sec)圖5.11數(shù)據(jù)庫(kù)存入用戶名、用戶密碼 登錄需要對(duì)用 戶名、用戶密碼進(jìn)行校驗(yàn)。<-> C O A Not secure 192.16.所 y登錄用戶名 用戶密碼確定用戶名、用戶密碼錯(cuò)誤=圖5. 12用戶信息錯(cuò)誤,返回錯(cuò)誤信息 注冊(cè)對(duì)用戶名 進(jìn)行校驗(yàn),防止重新注冊(cè)。圖5. 13用戶名被注冊(cè)5. 7文件測(cè)試服務(wù)器讀取內(nèi)存映射區(qū)中的文件數(shù)據(jù),作為響應(yīng)體發(fā)送給客戶端。S 今 C 。 A Not secure 192.1683.129:2333/. d . * n y圖5.14視頻測(cè)試192.168.3. R 192.168.3. R <-» C 6 A Not圖5. 15圖片測(cè)試6課題總結(jié)本文主要介紹了Linux環(huán)境下關(guān)于C+服務(wù)器開(kāi)發(fā)的相關(guān)技術(shù),分析了服務(wù)器的整體需求,并設(shè)計(jì)了一個(gè)結(jié)合 Reactor模式、epoll、非阻塞I/O以及線程池的高并發(fā)Web服務(wù)器。其中主要對(duì)服務(wù)器的高并發(fā)相關(guān)技術(shù)進(jìn)行了詳細(xì) 探討:epoll模式選擇、阻塞隊(duì)列實(shí)現(xiàn)原理、主線程與線程池的半同步/半異步模型、日志系統(tǒng)的同步/異步模式。 通過(guò)實(shí)驗(yàn)測(cè)試,可以得知本文設(shè)計(jì)的服務(wù)器在主流PC中運(yùn)行可以支持上萬(wàn)并發(fā),并且可以保證服務(wù)器穩(wěn)定運(yùn)行。同時(shí),本文設(shè)計(jì)的服務(wù)器還支持用戶登錄、注冊(cè)功能。工作線程通過(guò)數(shù)據(jù)庫(kù)連接池和RAH機(jī)制完成多線程模式 下對(duì)數(shù)據(jù)庫(kù)的有序訪問(wèn),并對(duì)客戶端的用戶名、用戶密碼進(jìn)行校驗(yàn)。對(duì)于文件傳輸,服務(wù)器通過(guò)內(nèi)存映射把資源文 件拷貝進(jìn)內(nèi)存,減少了程序?qū)ξ募x取的I/O操作,加快了文件傳輸速率。對(duì)于長(zhǎng)連接,服務(wù)器通過(guò)小頂堆實(shí)現(xiàn)了定 時(shí)器,完成了對(duì)超時(shí)連接的主動(dòng)釋放。本文設(shè)計(jì)的服務(wù)器雖然保證了高并發(fā)場(chǎng)景下的穩(wěn)定運(yùn)行,但依然存在一些應(yīng)用場(chǎng)景問(wèn)題。本文設(shè)計(jì)的服務(wù)器處 理的請(qǐng)求都是無(wú)狀態(tài)的,因此登錄功能會(huì)失去實(shí)際意義。有狀態(tài)場(chǎng)景需要服務(wù)器生成session并向客戶端返回 cookie, cookie的生成和session的保存在高并發(fā)場(chǎng)景下會(huì)變成一個(gè)新的難題。我將在后續(xù)工作中繼續(xù)改進(jìn),為服務(wù) 器的可用性提供更多支持。參考文獻(xiàn)1中國(guó)互聯(lián)網(wǎng)絡(luò)信息中心.第46次中國(guó)互聯(lián)網(wǎng)絡(luò)開(kāi)展?fàn)顩r統(tǒng)計(jì)報(bào)告R.北京:中共中央網(wǎng)絡(luò)平安和信息化委員會(huì) 辦公室,中華人民共和國(guó)國(guó)家互聯(lián)網(wǎng)信息辦公室,2020.2周炎濤,李立明.TCP/IP協(xié)議下網(wǎng)絡(luò)編程技術(shù)及其實(shí)現(xiàn)J.航空計(jì)算技術(shù),2002(03):126-128+132.3W. RichardStevens, BillFenner, AndrewM. Rudoff. UNIX網(wǎng)絡(luò)編程,第 1 卷,套接口API M.清華大學(xué)出版 社,2006.4W. RICHARDSTEVENS. TCP/IP詳解.卷1,協(xié)議機(jī)械工業(yè)出版社,2000.5MichaelKerrisk,凱利斯克,孫劍,等.Linux/UNIX系統(tǒng)編程手冊(cè)M.人民郵電出版社,2014. 6胥光輝,徐永森.同步阻塞線程的喚醒問(wèn)題研究J.計(jì)算機(jī)科學(xué),2002, 29(012):49-50.7 Gammo L , Brecht T , Shukla A , et al. Comparing and Evaluating epoll, select, and poll Event Mechanisms. Proceedings of Annual Linux Symposium, 2004.8Linux下基于EPOLL機(jī)制的海量網(wǎng)絡(luò)信息處理模型J.強(qiáng)激光與粒子束,2013, 25(Ozl):46-50. 9游 雙.Linux高性能服務(wù)器編程加.機(jī)械工業(yè)出版社,2013.10 Schmidt D C . Reactor - An Object Behavioral Pattern for Demultiplexing and Dispatching Handles for Synchronous Events. 1999.11李璞,張玲,胡術(shù),等.多線程環(huán)境下Reactor模式的研究與實(shí)現(xiàn)J.網(wǎng)絡(luò)新媒體技術(shù)