2012-05-18 172 views
34

起初,我必須問哪個州哪個州最好?例如一個實時MMORPG服務器。如果我爲每個客戶端創建一個線程而不是使用非阻塞套接字?或者如果我使用一個包含所有非阻塞套接字的線程呢?你能解釋我的優點嗎?我爲什麼要使用非阻塞或阻塞套接字?

回答

29

你的問題應該得到一個更長的討論,但這裏是在回答的短刺:

  • 使用阻塞套接字意味着只有一個插座可以在任何一個線程的任何時間(是活動的,因爲它會阻止在等待對於活動)
  • 使用阻塞套接字通常比非阻塞套接字更容易(異步編程往往更復雜)
  • 您可以按照您所述創建每個套接字1個線程,但是線程有開銷並且效率極低非阻塞解決方案;
  • 與非阻塞套接字,你可以處理客戶端的體積大得多:它可以擴展到幾十萬在一個單一的過程 - 但是代碼變得有點複雜

與非阻塞套接字(在Windows上)你有兩個選擇:

  • 輪詢
  • 事件基於
  • 重疊I/O

重疊的I/O會以最好的性能(成千上萬的套接字/進程)爲代價,而不會成爲正確理解和實現的最複雜模型。基本上歸結爲性能與編程的複雜性。

這就是爲什麼使用線程/插座模型是一個壞主意一個更好的解釋:

在Windows中,創建大量線程的效率非常低,因爲調度程序無法正確確定哪些線程應該接收處理器時間,哪些線程不應該。這與每個線程的內存開銷相結合意味着,在操作系統級別處理套接字連接之前很久,您將在OS級別耗盡內存(由於堆棧空間)和處理器週期(因爲管理線程的開銷) 。

+0

如果你在一個80路運行框中,你可以撕裂了數以百計的線程沒有問題。 –

+0

@John - 僅僅因爲可以創建數百個線程(如果你有足夠的內存),這並不意味着這是個好主意。其實這是一個壞主意! –

+9

我的觀點,不可否認的是,你不能僅僅在20處畫一條任意的線,而是調用超出「壞」的任何線程數。 –

8

我會記錄下來的話,對於差不多除了玩具程序之外的任何東西,都應該使用非阻塞套接字作爲理所當然的事。

阻塞套接字會導致一個嚴重的問題:如果在阻塞呼叫期間另一端(或其連接的任何部分)的計算機發生故障,則代碼將最終阻塞,直到IP堆棧超時。在一個典型的情況下,大約2分鐘,這在大多數情況下是完全不可接受的。阻止該阻塞調用的唯一方法是終止創建它的線程 - 但終止線程本身幾乎總是不可接受的,因爲在它之後進行清理並回收分配的任何資源實際上是不可能的。非阻塞套接字使得在/如果需要時中止呼叫是微不足道的,沒有對發起呼叫的線程做任何事情。

如果您使用多進程模型代替,則可以使阻塞套接口工作良好。在這裏,您只需爲每個連接創建一個全新的進程。該進程使用阻塞套接字,當/如果出現問題時,您只需要關閉整個進程。操作系統知道如何清理進程中的資源,因此清理不成問題。但它仍然有其他潛在的問題:1)你需要一個進程監視器來在需要時終止進程; 2)產生一個進程通常比創建一個套接字要貴一些。然而,這可能是一個可行的選擇,特別是當:

  1. 你正在處理少量的連接的同時
  2. 你通常做廣泛的處理對每個連接
  3. 你只處理與本地主機所以你對他們的連接速度快且可靠
  4. 你更關心的不是執行

優化開發3210

1.嗯,在技術上不是只有可能的方式,但大多數的替代品相對醜陋 - 更具體地說,我認爲當你添加代碼,以確定有問題,然後解決這個問題,你可能做了比使用非阻塞套接字更多的額外工作。

+6

可以通過將套接字從另一個線程上下文斷開而終止阻塞的套接字操作而不終止阻塞的線程。這將導致被阻止的操作失敗,並顯示錯誤代碼,然後被阻塞的線程可以繼續並執行其他操作,如正常清理。 –