1. Socket ack (acknowledgement)
Socket ack是指當socket接收到數據之后,發送一個ack字符串(比如$ACK)給socket發送方。這樣,socket發送方可以根據是否收到了ack判斷對方是否收到了數據。
Socket ack是顯示的在應用程序中加入的一種通訊協議。如果不使用ack,在socket通訊中,可能會丟失數據。
比如,socket client要連續的給socket server發送100條消息。如果我們在server收到第50條消息的時候,強行kill了server。那么查詢client端發送的log,可能client端成功發送了51條。只有當client端發送第52條消息的時候才遇到異常。這樣第51條消息就丟失了。
所以為了確保數據傳輸的準確性,我們可以引入ack協議。有時我們不僅要確保server不但收到了數據,而且還要保證server成功處理了數據。這時,可以等server成功處理完數據之后,再給client發ack。
2. Socket Keep Alive
Socket連接像數據庫連接一樣,屬于重量型資源。如果我們頻繁的創建socket、發送/接收數據、關閉socket,那么會有很大一部分時間浪費在socket的創建和關閉上。
所以,如果我們經常需要與同一個socket地址發送/接收數據時,應該考慮只創建一次socket,然后一直使用這個socket對象發送/接收數據。
3. Heartbeat
通常,我們會設置socket的receive 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, 1到4分鐘)就會自動消失.
我們需要特別注意CLOSE_WAIT 狀態:
1. 如果很長時間才消失,表明socket server處理太慢,很多client已經連接到server,發送完數據并close了。
2. 如果一直也不消失,表明有socket沒有正常close (對方已經close了)
5. SO_REUSEADDR Option
當socket主動調用close的時候,從上面可以知道,它最終會進入TIME_WAIT 狀態,需要過1到4分鐘,才能完全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上設置這個方法在Windows和Solaris下并不起作用。當socket處于TIME_WAIT 狀態時,重啟client仍然出現端口占用錯誤。上網搜索了很長時間,很多人都碰到了這個問題,可能是操作系統底層socket實現問題。因為測試使用C語言開發的socket client,同樣也有這個錯誤。有人說LINUX下好用,還有就是可以嘗試修改tcp_time_wait_interval來減小TIME_WAIT等待時間