基於winsock的阻塞和非阻塞通訊模型

2021-08-30 18:31:10 字數 2560 閱讀 5974

copy:[url]

這文章貌似不錯,sorry,習慣用貌似了~

摘要:在應用程式開發中,經常涉及各式各樣的機器的互動通訊問題。在windows作業系統下,可以使用mfc中的csocket,也可以使用以windows api為基礎的winsock等等。本文主要描述了winsock的兩種實現方式,即阻塞方式和非阻塞方式。並對應這兩種方式,描述了select模式和iocp模式。

關鍵字:winsock blocking nonblocking select模式 完成埠(iocp)模式

一、winsock簡介

對於眾多底層網路協議,winsock是訪問它們的首選介面。而且在每個win32平台上,winsock都以不同的形式存在著。winsock是網路程式設計介面,而不是協議。在win32平台上,winsock介面最終成為乙個真正的「與協議無關」介面,尤其是在winsock 2發布之後。

win32平台提供的最有用的特徵之一是能夠同步支援多種不同的網路協議。windows重定向器保證將網路請求路由到恰當的協議和子系統;但是,有了winsock,就可以編寫可直接使用任何一種協議的網路應用程式了。

在廣泛使用的windows平台下,winsock2被簡單包裝為一組龐大的api庫,通過wsa start up載入的關於winsock版本的資訊,初始了winsock相關的dll和lib,在成功呼叫了wsa startup之後,即可設計自主的與通訊有關的行為,當確認了執行完操作後,呼叫相應的wsa cleanup,釋放對winsock dll的引用次數。幾乎所有在windows平台下可使用的通訊框架都是由winsock擴充套件而來的。

這裡,之所以要再提windows下的winsock api程式設計,並不多餘,雖然也可以使用csocket或ace(adaptive communication environment)框架,但直接對較底層的本地作業系統api,會使我們更深的理解隱藏在框架下的實現,有時也可以解決一些實用問題。

本文涉及的主要是winsock中面向連線(tcp)部分。

二、阻塞和非阻塞

阻塞socket,又被稱為鎖定狀態的socket。非阻塞socket,又被稱為非鎖定狀態的socket。當呼叫乙個winsock api時, api的呼叫會耗費一定的cpu時間。當乙個操作完成之後才返回到使用者態,稱其為阻塞,反之,則為非阻塞。當呼叫api產生乙個基於流協議(tcp)的socket時,系統開闢了接收和傳送兩個緩衝區,所以操作實際都是使用者緩衝區和系統緩衝區的資料互動,並不是實際操作的完成,阻塞也是如此。如果綜合被tcp協議預設使用的nagle演算法,在資料報(tcp payload)比較短時,協議可能推遲其傳送,就不難想象了。

很多做過winsock通訊的人,都知道非阻塞的socket,也就是非同步socket的效率遠遠高於阻塞socket。可是除了直觀的認識外,底層的原理又是什麼呢?首先,阻塞的socket的最合理方式是:先知道socket控制代碼的可讀寫性,再發起動作。因為如果不做檢測而直接發起操作,那麼tcp的預設超時將讓你後悔不該這麼魯莽。於是,在一次動作中,完成了兩次從使用者態到系統態的狀態轉換,非同步的socket實際只告訴系統,所期望的操作,而不完成這種操作,系統會對每次提交的操作進行排隊。當指定的操作完成時,系統態跳轉至使用者態。這樣,只用了一次狀態轉換。其次,由於阻塞的特性,它比非阻塞占用了更多的cpu時間。

當然,程式總是要適合需求,有時阻塞的socket亦可滿足要求。

三、select模式

select模式是winsock中最常見的i/o模型。之所以稱其為「select模式」,是由於它的中心思想是利用select函式,實現對i/o的管理。利用select函式,判斷套接字上是否存在資料,或者能否向乙個套接字寫入資料。設計這個函式,唯一的目的是防止應用程式在套接字處於鎖定模式中時,在一次i/o繫結呼叫(如send或recv)過程中,被迫進入「鎖定」狀態。

對select不再贅述,msdn已經給出了詳細的解釋。這裡要討論下面兩個問題。

1.select的fd_set陣列可承受的最大數

細心的coder可能都注意到了msdn中對fd_setsize(winsock2.h)巨集的說明,可以在包含winsock2.h之前重新定義這個巨集,它將允許在乙個select操作中處理更多的socket控制代碼(>64)。但是為何定義就是64呢?這不僅是unix的遺留,更是select處理能力的一種衡量標準,過多的socket控制代碼檢測畢竟會影響到對已存在操作的socket的響應。乙個最合理的建議是,當程式執行在多cpu的機器上時,可以從邏輯上將socket控制代碼分為數個組,每組都小於64,用多個執行緒對每組socket進行select,這樣可以增加程式的響應能力。如果是單cpu,則可將fd_setsize增大至256,適當放大timeout。這時每個socket上吞吐量如果還很大,cpu利用率也據高不下,那就要考慮換種模型。

2.select在多埠偵聽中的應用

眾所周知,在winsock api中,accept()是乙個典型的阻塞操作,通常是建立乙個偵聽執行緒來單獨執行accept()。如果程式要完成多於乙個埠的偵聽,自然,建立數個執行緒也是乙個辦法,但這裡最好使用select。msdn中解釋了這種應用:readfds可以檢測出當前listening的socket控制代碼上是否有有效的connect發生。把本地listening的socket控制代碼置入readfds,當某個socket有效時,對它呼叫accept(),此時,發現accept()會立刻成功返回,乙個執行緒就完成了多埠的偵聽。

JAVA中的IO同步阻塞和NIO同步非阻塞

ionio 面向流面向緩衝 阻塞io 非阻塞io 無選擇器 1.面向流與面向緩衝2.阻塞與非阻塞 io3.選擇器 selector 最傳統的一種io模型,即在讀寫資料過程中會發生阻塞現象。當使用者執行緒發出io請求之後,核心會去檢視資料是否就緒,如果沒有就緒就會等待資料就緒,而使用者執行緒就會處於阻...

阻塞和非阻塞

在 windows 下的 socket 程式設計有兩個程式設計模型,阻塞和非阻塞。有時,他們也被叫做同步 阻 塞 和非同步 非阻塞 在 unix 中只支援阻塞模型。阻塞 indy 使用阻塞 socket 呼叫。阻塞呼叫很像乙個檔案的讀寫。當你讀資料或者寫資料時,直 到操作完成,函式才會返回。不同的是...

阻塞和非阻塞

在 windows 下的 socket 程式設計有兩個程式設計模型,阻塞和非阻塞。有時,他們也被叫做同步 阻 塞 和非同步 非阻塞 在 unix 中只支援阻塞模型。阻塞 indy 使用阻塞 socket 呼叫。阻塞呼叫很像乙個檔案的讀寫。當你讀資料或者寫資料時,直 到操作完成,函式才會返回。不同的是...