Socket Programming Considerations (2)

          Posted on 2010-07-28 09:23 天快黑了 閱讀(1670) 評論(1)  編輯  收藏 所屬分類: Socket
           

          1.       Socket ack (acknowledgement)

          Socket ack是指當socket接收到數據之后,發送一個ack字符串(比如$ACK)socket發送方。這樣,socket發送方可以根據是否收到了ack判斷對方是否收到了數據。

          Socket ack是顯示的在應用程序中加入的一種通訊協議。如果不使用ack,在socket通訊中,可能會丟失數據。

          比如,socket client要連續的給socket server發送100條消息。如果我們在server收到第50條消息的時候,強行killserver。那么查詢client端發送的log,可能client端成功發送了51條。只有當client端發送第52條消息的時候才遇到異常。這樣第51條消息就丟失了。

          所以為了確保數據傳輸的準確性,我們可以引入ack協議。有時我們不僅要確保server不但收到了數據,而且還要保證server成功處理了數據。這時,可以等server成功處理完數據之后,再給clientack

          2.       Socket Keep Alive

          Socket連接像數據庫連接一樣,屬于重量型資源。如果我們頻繁的創建socket、發送/接收數據、關閉socket,那么會有很大一部分時間浪費在socket的創建和關閉上。

          所以,如果我們經常需要與同一個socket地址發送/接收數據時,應該考慮只創建一次socket,然后一直使用這個socket對象發送/接收數據。

          3.       Heartbeat

          通常,我們會設置socketreceive timeout。這樣,如果我們一直打開著socket (keep alive) 而很長時間又沒有數據通訊,socket接收方就會timeout,最終導致打開的連接壞掉。

          如果很長時間沒有數據通訊,防火墻或代理服務器也可能會關閉打開的socket連接。

          所以為了保證打開的socket連接一直可用,如果一段時間沒有數據進行通訊(或指定一個時間間隔),我們可以顯示的發送一個heartbeat消息(比如: $HRT)給對方,從而保證連接不會被異常關閉。

          4.       Socket Close

          每一個socket對象會持有一個socket descriptor (其實就是file descriptor),操作系統對于socket descriptor有一個最大限制。因此當socket不再使用時,一定要記得關閉,即使socket連接失敗或出現異常,只要socket對象不為null,一定要記得關閉。

          下面圖顯示了,當socket關閉時,socket的狀態變化(socket狀態可以通過netstat命令查看)。更詳細的解釋,可以google一下。


          當主動一方調用close(先調用close)時的狀態變化:

          ESTABLISHED -> FIN_WAIT_1-> FIN_WAIT_2 -> TIME_WAIT -> CLOSED

          當被動一方調用close(后調用close)時的狀態變化:

          ESTABLISHED -> CLOSE_WAIT -> LAST_ACK -> CLOSED

          通常,TIME_WAIT 是正常狀態,過一段時間(2MSL, 14分鐘)就會自動消失.

          我們需要特別注意CLOSE_WAIT 狀態:

          1.   如果很長時間才消失,表明socket server處理太慢,很多client已經連接到server,發送完數據并close了。

          2.   如果一直也不消失,表明有socket沒有正常close (對方已經close)

          5.       SO_REUSEADDR Option

          socket主動調用close的時候,從上面可以知道,它最終會進入TIME_WAIT 狀態,需要過14分鐘,才能完全close

          socket處于TIME_WAIT 狀態時,它仍然占用正在使用的IP/PORT。這樣,如果我們的程序(比如socket server)使用了一個固定的IP/PORT,當socket處于TIME_WAIT 狀態時,程序將不能立即重啟,會出現端口占用錯誤。

          Socket提供了一個setReuseAddress()方法,可以設置當socket處于TIME_WAIT 狀態時,是否允許其它進程綁定這個端口。

          如果我們正在開發socket server,一定要記得調用ServerSocket.setReuseAddress(true).

          Client socket也有這個方法,而且有時可能需要指明client連接server時所使用的本地IP/PORT(一般不用指明,系統會隨機選擇一個PORT)。但實際測試,在client socket上設置這個方法在WindowsSolaris下并不起作用。當socket處于TIME_WAIT 狀態時,重啟client仍然出現端口占用錯誤。上網搜索了很長時間,很多人都碰到了這個問題,可能是操作系統底層socket實現問題。因為測試使用C語言開發的socket client,同樣也有這個錯誤。有人說LINUX下好用,還有就是可以嘗試修改tcp_time_wait_interval來減小TIME_WAIT等待時間

          Feedback

          # re: Socket Programming Considerations (2)[未登錄]  回復  更多評論   

          2010-07-28 17:35 by 匿名
          總體來說寫的不錯,看來對socket還是有比較好的理解的。
          關于setReuseAddress,這個還是設置成true比較好,
          但是要做好地址和端口的檢測工作。如果再加上跨平臺
          和多網卡就比較麻煩。

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          posts - 5, comments - 25, trackbacks - 0, articles - 1

          Copyright © 天快黑了

          主站蜘蛛池模板: 克东县| 榕江县| 民县| 兴隆县| 大同市| 大厂| 高安市| 拜泉县| 漯河市| 丹凤县| 长武县| 苗栗市| 图木舒克市| 黑水县| 兴业县| 客服| 盐池县| 墨玉县| 壤塘县| 蒙城县| 曲周县| 陕西省| 东阳市| 镇沅| 西华县| 沧州市| 天柱县| 临海市| 阿合奇县| 泰和县| 宜君县| 故城县| 芦溪县| 兴仁县| 屏东县| 英超| 阜新市| 姜堰市| 新余市| 老河口市| 雅江县|