|
概要 套接字是通信的基礎(chǔ),是支持網(wǎng)絡(luò)協(xié)議數(shù)據(jù)通信的基本接口。Winsocket 提供了一些有趣的I/O模型,有助于應(yīng)用程序通過(guò)一種“異步”方式,一次對(duì)一個(gè)或者多個(gè)套接字上進(jìn)行的通信加以管理。這些模型包括select(選擇)、WSAAsynSelect(異步選擇)、WSAEventSelect(事件選擇)、Overlapped I/O(重疊 I/O)以及Completion port(完成端口)。 ① select 模型: select模型是WinSock中應(yīng)用最廣泛的模型之一,核心就是select函數(shù),它可用于判斷套接字上是否存在數(shù)據(jù),或者能否向一個(gè)套接字寫(xiě)入數(shù)據(jù)。這個(gè)函數(shù)可以有效地防止應(yīng)用程序在套接字處于阻塞模式中時(shí),send或recv進(jìn)入阻塞狀態(tài);同時(shí)也可以防止產(chǎn)生大量的WSAEWOULDBLOCK錯(cuò)誤select的優(yōu)勢(shì)是能夠從單個(gè)線程的多個(gè)套接字上進(jìn)行多重連接及I/O。這就避免了伴隨阻塞套接字和多重連接的線程劇增。 ② WSAAsyncSelect 模型: 因?yàn)樗且韵榛A(chǔ)的,關(guān)鍵就是WSAAsyncSelect函數(shù),將socket消息發(fā)送到hWnd窗口上,然后在那里處理相應(yīng)的FD_READ、FD_WRITE等等消息。優(yōu)點(diǎn):WSAAsyncSelect和WSAEventSelect模型提供了讀寫(xiě)數(shù)據(jù)能力的異步通知,但他們不提供異步數(shù)據(jù)傳送,而重疊及完成端口提供異步數(shù)據(jù)的傳送。而且它可以在系統(tǒng)開(kāi)銷不大的情況下同時(shí)處理很多連接,而select模型還需要建立fd_set結(jié)構(gòu)。 缺點(diǎn):必須要使用一個(gè)窗口接收消息,如果處理成千上萬(wàn)的套接字就力不從心了。 ③ WSAEventSelect 模型: 這個(gè)也是以時(shí)間為基礎(chǔ)的網(wǎng)絡(luò)事件通知,但是與WSAAsyncSelect不同的是,它主要是由事件對(duì)象句柄完成的,而不是通過(guò)窗口。優(yōu)點(diǎn):不需要窗口。缺點(diǎn):每次只能等待64個(gè)事件,所以處理多個(gè)套接字時(shí)有必要組織一個(gè)線程池;所以伸縮性就不如后面的完成端口了。 ④ 重疊模型: 這個(gè)模型可以使程序能達(dá)到更佳的系統(tǒng)性能?;驹O(shè)計(jì)原理就是讓?xiě)?yīng)用程序使用重疊的數(shù)據(jù)結(jié)構(gòu),一次投遞一個(gè)或多個(gè)I/O請(qǐng)求。針對(duì)這些提交的請(qǐng)求,在他們完成之后,應(yīng)用程序可為他們提供服務(wù)。它又分為兩種實(shí)現(xiàn)方法:在事件中使用,還有就是完成例程。 ⑤ 完成端口: 完成端口提供了最好的伸縮性,往往可以使系統(tǒng)達(dá)到最好的性能,是處理成千上萬(wàn)的套接字的首選。從本質(zhì)上說(shuō),完成端口模型要求創(chuàng)建一個(gè)windows完成端口對(duì)象,該對(duì)象通過(guò)指定數(shù)量的線程,對(duì)重疊I/O請(qǐng)求進(jìn)行管理,以便為已經(jīng)完成的重疊I/O請(qǐng)求提供服務(wù)。 五種I/O模型的性能分析 重疊I/O 模型的另外幾個(gè)優(yōu)點(diǎn)在于,微軟針對(duì)重疊I/O 模 型提供了一些特有的擴(kuò)展函數(shù)。當(dāng)使用重疊I/O 模型時(shí),可以選擇使用不同的完成通知方式。 采用事 件對(duì)象通知的重疊I/O 模型是不可伸縮的,因?yàn)獒槍?duì)發(fā)出WSAWaitForMultipleEvents調(diào) 用的每個(gè)線程,該I/O 模型一次最多都只能支持6 4 個(gè) 套接字。假如想讓這個(gè)模型同時(shí)管理不止64 個(gè)套接字,必須創(chuàng)建額外的工作者線程,以便等待更多的事 件對(duì)象。因?yàn)椴僮飨到y(tǒng)同時(shí)能夠處理的事件對(duì)象是有限的,所以基于事件對(duì)象的I/O 模型不具備伸縮 性。 使用完 成例程通知的重疊I/O 模型,因?yàn)橐韵聨讉€(gè)原因,也不是開(kāi)發(fā)高性能服務(wù)器的最佳選擇。首先,許多擴(kuò) 展功能不允許使用APC (Asyncroneus Procedure Call ,異步過(guò)程調(diào)用)完成通知。其次,由于APC 在系統(tǒng)內(nèi) 部特有的處理機(jī)制,應(yīng)用程序線程可能無(wú)限等待而得不到完成通知。當(dāng)一個(gè)線程處于“ 可警告狀態(tài)” 時(shí),所有掛起的APC 按照先進(jìn)先出的順序(FIFO )接受處理?,F(xiàn)在考慮這樣一種情況,服務(wù)器已經(jīng)建立起了一個(gè)連接,并且調(diào)用含有完成例程指針的WSARecv投遞了一個(gè)重疊I/O 請(qǐng)求。當(dāng)有數(shù)據(jù)到 達(dá)時(shí)(即I/O 完成時(shí)),完成例程執(zhí)行并且再次調(diào)用WSARecv 拋 出另外一個(gè)重疊I/O 請(qǐng)求。一個(gè)APC 拋出 的I/O 操作需要一定的時(shí)間才能完成,所以這期間可能另外一個(gè)完成例程等待執(zhí)行(比如本次WSARecv還沒(méi)接收完時(shí),又有一個(gè)新的客戶接入并發(fā)來(lái)數(shù)據(jù)),因?yàn)檫€有更多的數(shù)據(jù)需要讀?。ㄉ弦粋€(gè)客戶發(fā) 來(lái)的數(shù)據(jù)尚未讀完)。只要(投遞WSARecv 的)那個(gè)套接字上還有“ 未決” (未接收完)的數(shù)據(jù),就會(huì)導(dǎo)致調(diào)用線程長(zhǎng)久阻 塞。 基于完 成端口通知的重疊I/O 模型是Windows NT 系 統(tǒng)提供的一個(gè)真正支持高伸縮性的I/O 模型。在上一章中,探討了Winsock 幾種常見(jiàn)的I/O 模型,并且說(shuō)明了當(dāng)應(yīng)對(duì) 大規(guī)??蛻暨B接時(shí),完成端口是最佳的選擇,因?yàn)樗峁┝俗詈玫纳炜s性。 對(duì)不同Winsock I/O 模型的性能測(cè)試結(jié)果如圖1 所 示。其中服務(wù)器采用Pentium4 1.7 GHz Xeon 的CPU ,768M 內(nèi)存;客戶端有3 臺(tái)PC ,配置分別是Pentium 2 233MHz ,128 MB 內(nèi)存,Pentium 2 350 MHz ,128 MB 內(nèi)存,Itanium733 MHz ,1 GB 內(nèi)存。服務(wù)器、客戶端安裝的操作系統(tǒng)都是Windows XP 。 1. 分析圖表1 提供的測(cè)試結(jié)果可知,在所用的I/O 模型中,阻塞模式性能最差。這個(gè)測(cè)試程序中,服務(wù)器為每個(gè)客戶創(chuàng)建兩個(gè)線程:一個(gè)負(fù)責(zé)處理數(shù)據(jù)的接收,一 個(gè)負(fù)責(zé)處理數(shù)據(jù)的發(fā)送。在多次測(cè)試中的共同問(wèn)題就是,阻塞模式難以應(yīng)對(duì)大規(guī)模的客戶連接,因?yàn)樗趧?chuàng)建線程上耗費(fèi)了太多的系統(tǒng)資源。因此,服務(wù)器創(chuàng)建太多 的線程后,再調(diào)用CreateThread 函數(shù)時(shí),將返回ERROR_NOT_ENOUGH_MEMORY 的 錯(cuò)誤,這個(gè)錯(cuò)誤碼提示內(nèi)存不夠。那些發(fā)出連接請(qǐng)求的客戶則收到WSAECONNREFUSED的錯(cuò) 誤提示,表示連接的嘗試被拒絕。 讓我們來(lái)看看監(jiān)聽(tīng)函數(shù)listen ,其原型如下: WINSOCK_API_LINKAGEint WSAAPI listen (SOCKETs, int backlog ); 參數(shù)一s 已綁定了地址的監(jiān)聽(tīng)套接字。 參數(shù)二backlog 指定了正在等待連接的最大隊(duì)列長(zhǎng)度。 參數(shù)backdog 非常重要, ? 因?yàn)橥耆赡芡瑫r(shí)出 現(xiàn)幾個(gè)對(duì)服務(wù)器的連接請(qǐng)求。例如,假定backlog參數(shù)為2 時(shí) 有三個(gè)客戶機(jī)同時(shí)發(fā)出連接請(qǐng)求,那么前兩個(gè)會(huì)被放在一個(gè)“ 等待處理” 隊(duì)列中,以便應(yīng)用程序依次為它們提供服務(wù)。而第三個(gè)連接的請(qǐng)求就會(huì)造成一個(gè)WSAECONNREFUSED錯(cuò)誤。一旦服務(wù)器接受了一個(gè)連接請(qǐng)求,那個(gè)連接請(qǐng)求就會(huì)從隊(duì)列中刪去,以便可以 繼續(xù)接收其他客戶發(fā)出的連接請(qǐng)求。即當(dāng)一個(gè)連接請(qǐng)求到來(lái)時(shí)隊(duì)列已滿,那么客戶將收到一個(gè)WSAECONNREFUSED錯(cuò) 誤。而backlog 參數(shù)本身的大小就存在著限制,這個(gè)限制是由協(xié)議提供者決定的。 故阻塞模式下,由于系 統(tǒng)資源的限制,其并發(fā)處理量是極難突破的。 2. 非阻塞模式表現(xiàn)出的性能要比阻塞模式稍好,但是占用了太多的CPU 處理時(shí)間。測(cè)試服務(wù)器將所有客戶對(duì)應(yīng)的socket 分 類放到FD_SET集合中,然后調(diào)用select函 數(shù)篩選出對(duì)應(yīng)集合中有事件發(fā)生的socket ,并對(duì)集合更新。接下來(lái)調(diào)用FD_ISSET 宏重新判斷一個(gè)套接字是否在原來(lái)加入的FD_SET 集 合中。隨著客戶連接數(shù)量的增多,這種模型的局限性逐漸凸現(xiàn)。僅僅為了判斷一個(gè)套接字是否有網(wǎng)絡(luò)事件發(fā)生,就需要對(duì)集合FD_SET執(zhí)行一次遍歷! 使用迭代搜索來(lái)對(duì)select 更新的FD_SET 進(jìn)行掃描,性能可以得 到一些提升。瓶頸在于,服務(wù)器必須能夠很快地掃描出FD_SET集合中的有網(wǎng)絡(luò)事件發(fā)生的套接字的 相關(guān)信息。針對(duì)這個(gè)問(wèn)題,可以使用更復(fù)雜的掃描算法,如哈希搜索,它的效率是極高的。還需要注意的一個(gè)問(wèn)題就是,非分頁(yè)池(即直接在物理內(nèi)存中分配的內(nèi) 存)的使用極高。這是因?yàn)锳FD (Ancillary Function Driver, 由afd.sys 提供的支持WindowsSockets 應(yīng)用程序的底層驅(qū)動(dòng)程序,其中運(yùn)行在內(nèi)核模式下afd.sys驅(qū)動(dòng)程序主要管理WinsockTCP/IP 通 信)和TCP 都將使用I/O 緩存,因?yàn)榉?wù) 器讀取數(shù)據(jù)的速度是有限的,相對(duì)于CPU 的處理速度而言,I/O 基 本是零字節(jié)的吞吐量。 3. 基于Windows 消 息機(jī)制的WSAAsyncSelect 模型能夠處理一定的客戶連接量,但是擴(kuò)展性也不是很好。因?yàn)?消息泵很快就會(huì)阻塞,降低了消息處理的速度。在幾次測(cè)試中,服務(wù)器只能處理大約1/3 的客戶端連 接。過(guò)多的客戶端連接請(qǐng)求都將返回錯(cuò)誤提示碼WSAECONNREFUSED ,說(shuō)明服務(wù)器不能及時(shí) 處理FD_ACCEPT 消息導(dǎo)致連接失敗,這樣監(jiān)聽(tīng)隊(duì)列中待處理的連接請(qǐng)求不致于爆滿。然而,通過(guò) 上表中的數(shù)據(jù)可以發(fā)現(xiàn),對(duì)那些已經(jīng)建立的連接,其平均吞吐量也是極低的(即使對(duì)于那些對(duì)比特率進(jìn)行了限制的客戶也如此)。 4. 基于事件通知的WSAEventSelect 模 型表現(xiàn)得出奇的不錯(cuò)。在所有的測(cè)試中,大多數(shù)時(shí)候,服務(wù)器基本能夠處理所有的客戶連接,并且保持著較高的數(shù)據(jù)吞吐量。這種模型的缺點(diǎn)是,每當(dāng)有一個(gè)新連接 時(shí),需要?jiǎng)討B(tài)管理線程池,因?yàn)槊總€(gè)線程只能夠等待64 個(gè)事件對(duì)象。當(dāng)客戶連接量超過(guò)64 個(gè)后再有新客戶接入時(shí),需要?jiǎng)?chuàng)建新的線程。在最后一次測(cè)試中,建立起了超過(guò)45,000個(gè)的客戶連接后,系統(tǒng)響應(yīng)速度變得非常緩慢。這時(shí)由于為處理大規(guī)模的客戶連接創(chuàng)建了大量的線程,占 用了過(guò)多的系統(tǒng)資源。791 個(gè)線程基本達(dá)到了極限,服務(wù)器不能再接受更多的連接了,原因是WSAENOBUFS:無(wú)可用的緩沖區(qū)空間,套接字無(wú)法創(chuàng)建。另外,客戶端程序也達(dá)到了極限,不能維持已經(jīng)建 立的連接。 使用事件通知的重疊I/O 模型和WSAEventSelect 模型在伸縮性上差不多。這兩種模型都依賴于等待事件通知的線程池,處理客戶通信 時(shí),大量線程上下文的切換是它們共同的制約因素。重疊I/O 模型和WSAEventSelect 模型的測(cè)試結(jié)果很相似,都表現(xiàn)得不錯(cuò),直到線程數(shù)量超過(guò)極限。 5. 最后是針對(duì)基于完成端口通知的重疊I/O 模 型的性能測(cè)試,由上表中數(shù)據(jù)可以看出,它是所有I/O 模型中性能最佳的。內(nèi)存使用率(包括用戶分頁(yè) 池和非分頁(yè)池)和支持的客戶連接量與基于事件通知的重疊I/O 模型和WSAEventSelect 模型基本相同。真正不同的地方,在于對(duì)CPU 的 占用。完成端口模型只占用了60% 的CPU , 但是在維持同樣規(guī)模的連接量時(shí),另外兩種模型(基于事件通知的重疊I/O 模型和WSAEventSelect 模型)占用更多的CPU 。 完成端口的另外一個(gè)明顯的優(yōu)勢(shì)是,它維持更大的吞吐量。 對(duì)以上各種模型進(jìn)行分析后,可以會(huì)發(fā)現(xiàn)客戶端與服務(wù)器數(shù)據(jù)通信機(jī)制本身存在的缺 陷是一個(gè)瓶頸。在以上測(cè)試中,服務(wù)器 被設(shè)計(jì)成只做簡(jiǎn)單的回應(yīng),即只是將客戶端發(fā)送過(guò)來(lái)的數(shù)據(jù)發(fā)送回去??蛻舳耍词褂斜忍芈氏拗疲┎煌5陌l(fā)送數(shù)據(jù)給服務(wù)器,這導(dǎo)致大量數(shù)據(jù)阻塞在服務(wù)器上與這 個(gè)客戶端對(duì)應(yīng)的套接字上(無(wú)論是TCP 緩沖區(qū)還是AFD 的 單套接字緩沖區(qū),它們都是在非分頁(yè)池上)。在最后三種性能比較好的模型中,同一時(shí)間只能執(zhí)行一個(gè)接受輸入操作,這意味著在大多數(shù)時(shí)間,還是有很多數(shù)據(jù)處于“ 未決” 狀態(tài)。可以修改服務(wù)器程序使其以異步方式接受 數(shù)據(jù),這樣一旦有數(shù)據(jù)達(dá)到,需要將數(shù)據(jù)緩存起來(lái)。這種方案的缺點(diǎn)是,當(dāng)一個(gè)客戶連續(xù)發(fā)送數(shù)據(jù)時(shí),異步接受到了大量的數(shù)據(jù)。這會(huì)導(dǎo)致其他的客戶無(wú)法接入,因 為調(diào)用線程和工作者線程都不能處理其他的事件或完成通知。通常情況下,調(diào)用非阻塞異步接收函數(shù),先返回WSAEWOULDBLOCK, 然后數(shù)據(jù)間斷性的傳輸,而不采取連續(xù)接收的方式。 從以上測(cè)試結(jié)果,可以看出WSAEventSelect 模型 和重疊I/O 模型是性能表現(xiàn)最佳的。兩種基于事件通知的模型中,創(chuàng)建線程池來(lái)等待事件完成通知并作 后續(xù)處理是很繁瑣的,但是并不影響以它們來(lái)架構(gòu)中型服務(wù)器的良好性能。當(dāng)線程的數(shù)量隨著客戶端連接數(shù)量而逐增時(shí),CPU 將 花費(fèi)大量時(shí)間在線程的上下文切換上,這將影響服務(wù)器的伸縮性,因?yàn)檫B接量達(dá)到一定數(shù)量后,便飽和了。完成端口模型提供了最佳的可擴(kuò)展性,因?yàn)镃PU 使用率低,其支持的客戶連接量相對(duì)其他模型最多。 I/O 模型的選擇 通過(guò)上一節(jié)對(duì)各種模型的測(cè)試分析,對(duì)于如何挑選最適合自己應(yīng)用程序的I/O 模 型已經(jīng)很明晰了。同開(kāi)發(fā)一個(gè)簡(jiǎn)單的運(yùn)行多線程的鎖定模式應(yīng)用相比,其他每種I/O 模型都需要更為復(fù) 雜的編程工作。因此,針對(duì)客戶機(jī)和服務(wù)器應(yīng)用開(kāi)發(fā)模型的選擇,有以下原則。 1. 客戶端 若打算開(kāi)發(fā)一個(gè)客戶機(jī)應(yīng)用,令其同時(shí)管理一個(gè)或多個(gè)套接字,那么建議采用重疊I/O 或WSAEventSelect 模型,以便在一定程度上提升性能。然而,假如開(kāi)發(fā)的是一個(gè)以Windows為基礎(chǔ)的應(yīng)用程序,要進(jìn)行窗口消息的管理,那么WSAAsyncSelect模 型恐怕是一種最好的選擇,因?yàn)閃SAAsyncSelect 本身便是從Windows 消息模型借鑒來(lái)的。采用這種模型,程序需具備消息處理功能。 2. 服務(wù)器端 若開(kāi)發(fā)的是一個(gè)服務(wù)器應(yīng)用,要在一個(gè)給定的時(shí)間,同時(shí)控制多個(gè)套接字,建議采用 重疊I/O 模型,這同樣是從性能角度考慮的。但是,如果服務(wù)器在任何給定的時(shí)間,都會(huì)為大量I/O 請(qǐng)求提供服務(wù),便應(yīng)考慮使用I/O 完成端口模型, 從而獲得更佳的性能。 |
|
|
來(lái)自: 阿鼎的圖書(shū)館 > 《network》