一、摘要
通過最近一段時間應用C#進行網絡通信,了解了C#實現網絡通信的方法,尤其是套接字socket的使用,接下來的幾篇文章對套接字的使用及常用傳輸協議TCP、UDP的C#實現做一下梳理與總結。該篇博文僅對socket涉及到的名詞進行解釋與區別。
二、實驗平台
Visual Studio 2010
三、實驗原理
這里以最常用的C/S模式作為范例,首先,服務端有一個進程(或多個進程)在指定的端口等待客戶來連接,服務程序等待客戶的連接信息,一旦連接上之后,就可以按設計的數據交換方法和格式進行數據傳輸。
在進行socket編程時,常遇到的名詞還有同步、異步、阻塞和非阻塞等,下面對其做一下梳理。另外,需要說明的是,這些概念並不局限於socktet。
3.1 同步與異步
(1) 同步,可以理解為在執行完一個函數或方法之后,一直等待系統返回值或消息,這時程序是處於等待狀態,只有接收到返回的值或消息后才往下執行其他的命令。
(2) 異步,執行完函數或方法后,不必阻塞性地等待返回值或消息,只需要向系統委托一個異步過程,那么當系統接收到返回值或消息時,系統會自動觸發委托的異步過程,從而完成一個完整的流程。
在網上看到一個比較形象的例子,摘錄如下:
設想你是一位體育老師,需要測驗100位同學的400米成績。你當然不會讓100位同學一起起跑,因為當同學們返回終點時,你根本來不及掐表記錄各位同學的成績。如果你每次讓一位同學起跑並等待他回到終點你記下成績后再讓下一位起跑,直到所有同學都跑完。恭喜你,你已經掌握了同步阻塞模式。
你設計了一個函數,傳入參數是學生號和起跑時間,返回值是到達終點的時間。你調用該函數100次,就能完成這次測驗任務。這個函數是同步的,因為只要你調用它,就能得到結果;這個函數也是阻塞的,因為你一旦調用它,就必須等待,直到它給你結果,不能去干其他事情。
如果你一邊每隔10秒讓一位同學起跑,直到所有同學出發完畢;另一邊每有一個同學回到終點就記錄成績,直到所有同學都跑完。恭喜你,你已經掌握了異步非阻塞模式。
你設計了兩個函數,其中一個函數記錄起跑時間和學生號,該函數你會主動調用100次;另一個函數記錄到達時間和學生號,該函數是一個事件驅動的callback函數,當有同學到達終點時,你會被動調用。你主動調用的函數是異步的,因為你調用它,它並不會告訴你結果;這個函數也是非阻塞的,因為你一旦調用它,它就馬上返回,你不用等待就可以再次調用它。但僅僅將這個函數調用100次,你並沒有完成你的測驗任務,你還需要被動等待調用另一個函數100次。
當然,你馬上就會意識到,同步阻塞模式的效率明顯低於異步非阻塞模式。那么,誰還會使用同步阻塞模式呢?
不錯,異步模式效率高,但更麻煩,你一邊要記錄起跑同學的數據,一邊要記錄到達同學的數據,而且同學們回到終點的次序與起跑的次序並不相同,所以你還要不停地在你的成績冊上查找學生號。忙亂之中你往往會張冠李戴。
你可能會想出更聰明的辦法:你帶了很多塊秒表,讓同學們分組互相測驗。恭喜你!你已經掌握了多線程同步模式!
每個拿秒表的同學都可以獨立調用你的同步函數,這樣既不容易出錯,效率也大大提高,只要秒表足夠多,同步的效率也能達到甚至超過異步。
可以理解,你現的問題可能是:既然多線程同步既快又好,異步模式還有存在的必要嗎?
很遺憾,異步模式依然非常重要,因為在很多情況下,你拿不出很多秒表。你需要通信的對端系統可能只允許你建立一個socket連接,很多金融、電信行業的大型業務系統都如此要求。
以上即是socket編程中同步與異步的區別。
3.2 阻塞與非阻塞
(1)阻塞調用是指調用結果返回之前,當前線程會被掛起。函數只有在得到結果之后才會返回。
(2)非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回。
3.3 同步與阻塞的區別
針對上述的闡述,有人也許會把阻塞和同步等同起來,實際上他是不同的。同步異步與阻塞和非阻塞是兩種不同的概念來着,同步異步指的是通信模式,而阻塞和非阻塞指的是在接收和發送時是否等待動作完成才返回,所以不能混淆這四個詞。