生活随笔
收集整理的這篇文章主要介紹了
java socket 判断Socket连接失效
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
要判斷socket連接鏈路是否可用時,不能通過socket.isClosed()?和?socket.isConnected()?方法判斷,要通過心跳包 socket.sendUrgentData(0xFF) 。
當第一次連接成功后,?socket.isClosed() ==false,?socket.isConnected()==true,只有在自己端代碼中顯示調用socket.close()方法時,socket.isClosed() ==true。
而鏈路的不可用時,自己端的socket是不知道的,仍然是 socket.isClosed() ==false,?socket.isConnected()==true。
要通過心跳包 socket.sendUrgentData(0xFF)? 進行測驗。
?
我們來看如下代碼運行后再繼續:
服務端:
Java代碼??
package?com.service;??import?java.net.*;??public?class?DstService?{??????public?static?void?main(String[]?args)?{??????????try?{?????????????????????????????????????ServerSocket?ss?=?new?ServerSocket(8001);??????????????????????????Socket?s?=?ss.accept();??????????????????????????new?Thread(new?DstServiceImpl(s)).start();??????????}?catch?(Exception?e)?{??????????????e.printStackTrace();??????????}??????}??}?? 然后我們來看執行類,執行類在收到連接5秒后中斷連接:
?
Java代碼??
package?com.service;??import?java.net.Socket;??public?class?DstServiceImpl?implements?Runnable?{??????Socket?socket?=?null;??????public?DstServiceImpl(Socket?s)?{??????????this.socket?=?s;??????}??????public?void?run()?{??????????try?{??????????????int?index?=?1;??????????????while?(true)?{??????????????????????????????????if?(index?>?5)?{??????????????????????socket.close();??????????????????????System.out.println("服務端已經將連接關閉!");??????????????????????break;??????????????????}??????????????????index++;??????????????????Thread.sleep(1?*?1000);??????????????}??????????}?catch?(Exception?e)?{??????????????e.printStackTrace();??????????}??????}??}?? 我們在寫一個客戶端進行實驗:
Java代碼??
package?com.client;??import?java.net.*;??public?class?DstClient?{??????public?static?void?main(String[]?args)?{??????????try?{??????????????Socket?socket?=?new?Socket("127.0.0.1",?8001);??????????????socket.setKeepAlive(true);??????????????socket.setSoTimeout(10);??????????????while?(true)?{??????????????????System.out.println(socket.isBound());??????????????????System.out.println(socket.isClosed());??????????????????System.out.println(socket.isConnected());??????????????????System.out.println(socket.isInputShutdown());??????????????????System.out.println(socket.isOutputShutdown());??????????????????System.out.println("------------------------");??????????????????Thread.sleep(3?*?1000);??????????????}??????????}?catch?(Exception?e)?{??????????????e.printStackTrace();??????????}??????}??}?? ??
至于輸出結果,雖然服務端已經中斷連接,但是客戶端一直輸出下面內容:
Xml代碼??
true??false??true??false??false??------------------------?? ?從連接對象的屬性信息來看,連接似乎沒有中斷。但實際雖然內存對象可用,但是物理連接已經失效。所以和網上其他抄襲來抄襲去的說法一樣,靠連接對象屬性來判斷連接的可用性是不可行的。
大家會說那就判斷調用read方法是否報錯唄。我之前有文章已經討論了關于調用網絡里面流的一些內容,在沒有判斷這個流可用之前,我們是不會調用read方法的,當然具體你是怎么做的我不知道我在說我的情況!
讀取網絡數據流時的那個方法是這樣的:
Java代碼??
public?static?byte[]?inputStreamToByte(InputStream?inStream)??????????throws?Exception?{??????int?count?=?0;??????int?haveCheck?=?0;??????????while?(count?==?0)?{??????????count?=?inStream.available();??????????haveCheck++;??????????if?(haveCheck?>=?50)??????????????return?null;??????}??????byte[]?b?=?new?byte[count];??????inStream.read(b);??????return?b;??}?? ?就是說我們不會直接調用read方法,而available方法在流沒有完整和網絡中斷時都會返回0,不會報錯。
就是說就算你設置超時時間設置保持連接這些東西,只要你沒有調用read的機會,你的程序就不會出問題。當然如果程序一直不調用read方法,那這個程序可真的夠扯淡的了。
其實只要在使用這個連接的時候判斷這個連接的可用性就行了,不要等著什么超時。
判斷連接可用雖然網上一大片,其實就是那么回事,手動發送心跳包。
Java代碼??
socket.sendUrgentData(0xFF);? ?如果你的連接已經中斷,那么這個方法就會報錯。
至于什么是心跳包,直接上理論吧。
心跳包就是在客戶端和服務器間定時通知對方自己狀態的一個自己定義的命令字,按照一定的時間間隔發送,類似于心跳,所以叫做心跳包。 用來判斷對方(設備,進程或其它網元)是否正常運行,采用定時發送簡單的通訊包,如果在指定時間段內未收到對方響應,則判斷對方已經離線。用于檢測TCP的異常斷開。基本原因是服務器端不能有效的判斷客戶端是否在線,也就是說,服務器無法區分客戶端是長時間在空閑,還是已經掉線的情況。所謂的心跳包就是客戶端定時發送簡單的信息給服務器端告訴它我還在而已。代碼就是每隔幾分鐘發送一個固定信息給服務端,服務端收到后回復一個固定信息如果服務端幾分鐘內沒有收到客戶端信息則視客戶端斷開。 比如有些通信軟件長時間不使用,要想知道它的狀態是在線還是離線就需要心跳包,定時發包收包。發包方:可以是客戶也可以是服務端,看哪邊實現方便合理,一般是客戶端。服務器也可以定時發心跳下去。一般來說,出于效率的考慮,是由客戶端主動向服務器端發包,而不是服務器向客戶端發。客戶端每隔一段時間發一個包,使用TCP的,用send發,使用UDP的,用sendto發,服務器收到后,就知道當前客戶端還處于“活著”的狀態,否則,如果隔一定時間未收到這樣的包,則服務器認為客戶端已經斷開,進行相應的客戶端斷開邏輯處理!
當然不能單純理解心跳包就是往對方放松數據,因為心跳包是用于狀態驗證的,不是真實的數據。
我們來看如下例子,服務端不變:
Java代碼??
package?com.client;??import?java.net.*;??public?class?DstClient?{??????public?static?void?main(String[]?args)?{??????????try?{??????????????Socket?socket?=?new?Socket("127.0.0.1",?8001);??????????????socket.setKeepAlive(true);??????????????socket.setSoTimeout(10);??????????????while?(true)?{??????????????????socket.sendUrgentData(0xFF);?????????????????System.out.println("目前是正常的!");??????????????????Thread.sleep(3?*?1000);??????????????}??????????}?catch?(Exception?e)?{??????????????e.printStackTrace();??????????}??????}??}?? ?看到控制臺的輸出:
Java代碼??
目前是正常的!??目前是正常的!??java.net.SocketException:?Invalid?argument:?send??????at?java.net.PlainSocketImpl.socketSendUrgentData(Native?Method)??????at?java.net.PlainSocketImpl.sendUrgentData(PlainSocketImpl.java:550)??????at?java.net.Socket.sendUrgentData(Socket.java:928)??????at?com.client.DstClient.main(DstClient.java:14)?? ?那就是說,只要你的服務端斷了,調用方法就會出錯!
至于我說的他不會作為可見的數據你可以更改服務端代碼打印客戶端內容,你會發現服務端不會將心跳包內容展示給你!
Java代碼??
InputStream?ips?=?socket.getInputStream();??byte[]?bt?=?inputStreamToByte(ips);??if(null?!=?bt)??????System.out.println(new?String(bt));??else??????System.out.println("Bt?is?null");??System.out.println("****************************");??
轉載于:https://www.cnblogs.com/panchanggui/p/9664876.html
總結
以上是生活随笔為你收集整理的java socket 判断Socket连接失效的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。