Socket通訊總結

1、  爲了增加效率,可以考慮採用無異常的函數
在.net2.0中Socket.Send,Socket.Receive 有了無異常的函數
Socket.Send(Byte[], Int32, Int32, SocketFlags, SocketError)
Socket.Receive(Byte[], Int32, Int32, SocketFlags, SocketError)
減少不必要的異常,就等於增加效率。

2、Socket.Connected 不是當前的Socket狀態
MSDN原文:獲取一個值,該值指示 Socket 是在上次 Send 還是 Receive 操作時連接到遠程主機。
應當如何解決呢?

同樣MSDN也告訴了我們:
Connected 屬性的值反映最近操作時的連接狀態。如果您需要確定連接的當前狀態,請進行非阻止、零字節的 Send 調用。 如果該調用成功返回或引發 WAEWOULDBLOCK 錯誤代碼 (10035),則該套接字仍然處於連接狀態;否則,該套接字不再處於連接狀態。
3、要用Socket.Poll判斷是否可以接收,不要用Socket.Available
雖然Socket.Available可以偷窺到當前Recv緩衝區字節數,而且Available是Poll速度的兩倍,但是MSDN說到:如果遠程主機使用 Shutdown 方法關閉了 Socket 連接,並且所有可用數據均已收到,則 Receive 方法將立即完成並返回零字節。
所以當網絡斷開的時候單純使用Socket.Available判斷是否recv到數據會存在不知道客戶端已經斷開Bug
補充:不推薦使用Socket.Poll對Socket的列表遍歷,應當使用Socket.Select(或者其他模型),Socket.Poll是對Socket.Select的封裝,執行Socket.Poll耗時是非阻塞Socket.Recv的三倍。
4、非阻塞模式不能採用Receive的返回值表示是否斷開
第3條說道:如果遠程主機使用 Shutdown 方法關閉了 Socket 連接,並且所有可用數據均已收到,則 Receive 方法將立即完成並返回零字節。但這並不能阻塞模式說明Socket已經斷開,這一條和C的recv函數不同,需要特別注意。需要判斷out出來的SocketError,當不爲SocketError.Success、SocketError.Interrupted和SocketError.WouldBlock時就可以認爲網絡已經斷開。
5、Send可能出現緩衝區滿的情況
判斷out出來的SocketError,如果等於SocketError.WouldBlock,則是Send緩衝區已滿,應斷開該Socket,否則影響整體速度,而不應當again, 反過來說允許的錯誤碼只有SocketError.Interrupted,此時可以重來一次。
6、主動斷開Socket
MSDN說道:如果當前使用的是面向連接的 Socket,則必須先調用 Shutdown 方法,然後才能關閉 Socket。這可以確保在已連接的套接字關閉之前,已發送和接收該套接字上的所有數據。
所以,網絡庫的Close函數可以封裝爲先調用 Shutdown(SocketShutdown.Both),在調用Close()。
7、Socket已經關閉(Close)但不能在另一端斷開
一端Scoket已經關閉了,但另一端短時間內仍可以發送數據!這個問題還沒有找到解決辦法的,但原因已知,在《Windows網絡編程技術》一書(P139-P140)中說道:被動關閉的情況下,應用程序會從對方那裏接收一個FIN包,並用一個ACK包做出響應。此時,應用程序的套接字會變成ClOSE_WAIT狀態。由於對方已關閉自己的套接字,所以不能再發送數據了。但應用程序卻不同,它能一直髮送數據,直到對方的套接字已關閉爲止。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章