天天看點

java socket異常java.net.SocketException

  最近看到java socket,在連接配接已關閉下,調用read或write會報java.net.SocketException異常,對這些異常産生原因我進行了一下詳細了解。

  首先,得了解下連接配接關閉要分為兩種情況:有序釋放連接配接和異常終止。

  有序釋放連接配接從TCP傳輸層看了解為兩個階段:A決定停止向B發資料,于是A主動發送fin資訊給B,B的TCP協定棧收完fin之前A發來的所有資料後,會收到fin資訊,于是B就知道A之後沒有資料會再過來了,一但B端讀取完fin資訊之前的所有資料,B再調用read讀取就會傳回-1,-1用來表明流的end。這一個過程被稱為TCP半關閉,此時主動關閉方A應該仍然能正常接收B的資料。同樣的,由B主動向A發送fin,完成另一半的關閉後,這樣整個TCP連接配接就有序釋放,徹底關閉了。

  異常終止使用RST(Reset)消息,任何一方發出RST,就意味着連接配接将中止,任意一端TCP發送或接收緩沖區的資訊将被TCP協定棧丢棄。

  預設的linger配置是走第一個有序釋放連接配接。但是有個特别需要注意的一點:java的

Socket.close()

和TCP 

FIN

消息語義是不一緻的, TCP的FIN意味着隻是關閉了主動方一側的寫,而應用層java的

Socket.close()

 卻意味着直接結束了讀和寫。這個差別會帶來一個有意思的異常java.net.SocketException。

  當A調用socket.close,發送fin消息給B後,此時B仍然發送資料給A,會産生什麼情況?從TCP層面來看,這是完全可以的,因為隻是半關閉。但是調用了java socket.close意味着應用層已經不能再接收資料了,這個socket已經完全關閉了。此時A的TCP協定棧會發送RST消息給B強制終止連接配接。收到RST後,此時若B再次發送資料給A,B就會報java.net.SocketException異常(B第一次write,TCP協定棧收到RST,但是應用無感覺,第二次write,B就會抛出異常)。