天天看點

Java Socket 網絡程式設計常見異常

1.java.net.SocketTimeoutException.這個異常比較常見,socket逾時。一般有2個地方會抛出這個,一個是connect的時候,這個逾時參數由connect(SocketAddress endpoint,int timeout)中的後者來決定,還有就是setSoTimeout(int timeout),這個是設定讀取的逾時時間。它們設定成0均表示無限大。

2.java.net.BindException:Address already in use: JVM_Bind。該異常發生在伺服器端進行new ServerSocket(port) 或者socket.bind(SocketAddress bindpoint)操作時。

原因:與port一樣的一個端口已經被啟動,并進行監聽。此時用netstat –an指令,可以看到一個Listending狀态的端口。隻需要找一個沒有被占用的端口就能解決這個問題。

3.java.net.ConnectException: Connection refused: connect。該異常發生在用戶端進行new Socket(ip, port)或者socket.connect(address,timeout)操作時.

原因:指定ip位址的機器不能找到(也就是說從目前機器不存在到指定ip路由),或者是該ip存在,但找不到指定的端口進行監聽。應該首先檢查用戶端的ip和port是否寫錯了,假如正确則從用戶端ping一下伺服器看是否能ping通,假如能ping通(服務伺服器端把ping禁掉則需要另外的辦法),則看在伺服器端的監聽指定端口的程式是否啟動。

4.java.net.SocketException: Socket is closed,該異常在用戶端和伺服器均可能發生。異常的原因是己方主動關閉了連接配接後(調用了Socket的close方法)再對網絡連接配接進行讀寫操作。

5.java.net.SocketException: Connection reset或者Connect reset by peer:Socket write error。該異常在用戶端和伺服器端均有可能發生,引起該異常的原因有兩個,第一個就是假如一端的Socket被關閉(或主動關閉或者因為異常退出而引起的關閉),另一端仍發送資料,發送的第一個資料包引發該異常(Connect reset by peer)。另一個是一端退出,但退出時并未關閉該連接配接,另一端假如在從連接配接中讀資料則抛出該異常(Connection reset)。簡單的說就是在連接配接斷開後的讀和寫操作引起的。

對于伺服器,一般的原因可以認為:

a) 伺服器的并發連接配接數超過了其承載量,伺服器會将其中一些連接配接主動Down掉.

b) 在資料傳輸的過程中,浏覽器或者接收用戶端關閉了,而服務端還在向用戶端發送資料。

6.java.net.SocketException: Broken pipe。該異常在用戶端和伺服器均有可能發生。在抛出SocketExcepton:Connect reset by peer:Socket write error後,假如再繼續寫資料則抛出該異常。前兩個異常的解決方法是首先確定程式退出前關閉所有的網絡連接配接,其次是要檢測對方的關閉連接配接操作,發現對方關閉連接配接後自己也要關閉該連接配接。

對于4和5這兩種情況的異常,需要特别注意連接配接的維護。在短連接配接情況下還好,如果是長連接配接情況,對于連接配接狀态的維護不當,則非常容易出現異常。基本上對長連接配接需要做的就是:

a) 檢測對方的主動斷連(對方調用了Socket的close方法)。因為對方主動斷連,另一方如果在進行讀操作,則此時的傳回值是-1。是以一旦檢測到對方斷連,則主動關閉己方的連接配接(調用Socket的close方法)。

b) 檢測對方的當機、異常退出及網絡不通,一般做法都是心跳檢測。雙方周期性的發送資料給對方,同時也從對方接收“心跳資料”,如果連續幾個周期都沒有收到對方心跳,則可以判斷對方或者當機或者異常退出或者網絡不通,此時也需要主動關閉己方連接配接;如果是用戶端可在延遲一定時間後重新發起連接配接。雖然Socket有一個keep alive選項來維護連接配接,如果用該選項,一般需要兩個小時才能發現對方的當機、異常退出及網絡不通。

7.java.net.SocketException: Too many open files

原因: 作業系統的中打開檔案的最大句柄數受限所緻,常常發生在很多個并發使用者通路伺服器的時候。因為為了執行每個使用者的應用伺服器都要加載很多檔案(new一個socket就需要一個檔案句柄),這就會導緻打開檔案的句柄的缺乏。

解決方式:

a) 盡量把類打成jar包,因為一個jar包隻消耗一個檔案句柄,如果不打包,一個類就消耗一個檔案句柄。 

b) java的GC不能關閉網絡連接配接打開的檔案句柄,如果沒有執行close()則檔案句柄将一直存在,而不能被關閉。也可以考慮設定socket的最大打開數來控制這個問題。對作業系統做相關的設定,增加最大檔案句柄數量。ulimit -a可以檢視系統目前資源限制,ulimit -n 10240則可以修改,這個修改隻對目前視窗有效。

     本文轉自xyz_lmn51CTO部落格,原文連結:http://blog.51cto.com/xyzlmn/1230798,如需轉載請自行聯系原作者