生活随笔
收集整理的這篇文章主要介紹了
java socket 判断Socket连接失效
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
?
要判斷socket連接鏈路是否可用時,不能通過socket.isClosed()?和?socket.isConnected()?方法判斷,要通過心跳包 socket.sendUrgentData(0xFF) 。
當(dāng)?shù)谝淮芜B接成功后,?socket.isClosed() ==false,?socket.isConnected()==true,只有在自己端代碼中顯示調(diào)用socket.close()方法時,socket.isClosed() ==true。
而鏈路的不可用時,自己端的socket是不知道的,仍然是 socket.isClosed() ==false,?socket.isConnected()==true。
要通過心跳包 socket.sendUrgentData(0xFF)? 進(jìn)行測驗。
?
我們來看如下代碼運行后再繼續(xù):
服務(wù)端:
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();??????????}??????}??}?? 然后我們來看執(zhí)行類,執(zhí)行類在收到連接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("服務(wù)端已經(jīng)將連接關(guān)閉!");??????????????????????break;??????????????????}??????????????????index++;??????????????????Thread.sleep(1?*?1000);??????????????}??????????}?catch?(Exception?e)?{??????????????e.printStackTrace();??????????}??????}??}?? 我們在寫一個客戶端進(jìn)行實驗:
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();??????????}??????}??}?? ??
至于輸出結(jié)果,雖然服務(wù)端已經(jīng)中斷連接,但是客戶端一直輸出下面內(nèi)容:
Xml代碼??
true??false??true??false??false??------------------------?? ?從連接對象的屬性信息來看,連接似乎沒有中斷。但實際雖然內(nèi)存對象可用,但是物理連接已經(jīng)失效。所以和網(wǎng)上其他抄襲來抄襲去的說法一樣,靠連接對象屬性來判斷連接的可用性是不可行的。
大家會說那就判斷調(diào)用read方法是否報錯唄。我之前有文章已經(jīng)討論了關(guān)于調(diào)用網(wǎng)絡(luò)里面流的一些內(nèi)容,在沒有判斷這個流可用之前,我們是不會調(diào)用read方法的,當(dāng)然具體你是怎么做的我不知道我在說我的情況!
讀取網(wǎng)絡(luò)數(shù)據(jù)流時的那個方法是這樣的:
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;??}?? ?就是說我們不會直接調(diào)用read方法,而available方法在流沒有完整和網(wǎng)絡(luò)中斷時都會返回0,不會報錯。
就是說就算你設(shè)置超時時間設(shè)置保持連接這些東西,只要你沒有調(diào)用read的機(jī)會,你的程序就不會出問題。當(dāng)然如果程序一直不調(diào)用read方法,那這個程序可真的夠扯淡的了。
其實只要在使用這個連接的時候判斷這個連接的可用性就行了,不要等著什么超時。
判斷連接可用雖然網(wǎng)上一大片,其實就是那么回事,手動發(fā)送心跳包。
Java代碼??
socket.sendUrgentData(0xFF);? ?如果你的連接已經(jīng)中斷,那么這個方法就會報錯。
至于什么是心跳包,直接上理論吧。
心跳包就是在客戶端和服務(wù)器間定時通知對方自己狀態(tài)的一個自己定義的命令字,按照一定的時間間隔發(fā)送,類似于心跳,所以叫做心跳包。 用來判斷對方(設(shè)備,進(jìn)程或其它網(wǎng)元)是否正常運行,采用定時發(fā)送簡單的通訊包,如果在指定時間段內(nèi)未收到對方響應(yīng),則判斷對方已經(jīng)離線。用于檢測TCP的異常斷開。基本原因是服務(wù)器端不能有效的判斷客戶端是否在線,也就是說,服務(wù)器無法區(qū)分客戶端是長時間在空閑,還是已經(jīng)掉線的情況。所謂的心跳包就是客戶端定時發(fā)送簡單的信息給服務(wù)器端告訴它我還在而已。代碼就是每隔幾分鐘發(fā)送一個固定信息給服務(wù)端,服務(wù)端收到后回復(fù)一個固定信息如果服務(wù)端幾分鐘內(nèi)沒有收到客戶端信息則視客戶端斷開。 比如有些通信軟件長時間不使用,要想知道它的狀態(tài)是在線還是離線就需要心跳包,定時發(fā)包收包。發(fā)包方:可以是客戶也可以是服務(wù)端,看哪邊實現(xiàn)方便合理,一般是客戶端。服務(wù)器也可以定時發(fā)心跳下去。一般來說,出于效率的考慮,是由客戶端主動向服務(wù)器端發(fā)包,而不是服務(wù)器向客戶端發(fā)。客戶端每隔一段時間發(fā)一個包,使用TCP的,用send發(fā),使用UDP的,用sendto發(fā),服務(wù)器收到后,就知道當(dāng)前客戶端還處于“活著”的狀態(tài),否則,如果隔一定時間未收到這樣的包,則服務(wù)器認(rèn)為客戶端已經(jīng)斷開,進(jìn)行相應(yīng)的客戶端斷開邏輯處理!
當(dāng)然不能單純理解心跳包就是往對方放松數(shù)據(jù),因為心跳包是用于狀態(tài)驗證的,不是真實的數(shù)據(jù)。
我們來看如下例子,服務(wù)端不變:
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)?? ?那就是說,只要你的服務(wù)端斷了,調(diào)用方法就會出錯!
至于我說的他不會作為可見的數(shù)據(jù)你可以更改服務(wù)端代碼打印客戶端內(nèi)容,你會發(fā)現(xiàn)服務(wù)端不會將心跳包內(nèi)容展示給你!
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("****************************");??
轉(zhuǎn)載于:https://www.cnblogs.com/panchanggui/p/9664876.html
總結(jié)
以上是生活随笔為你收集整理的java socket 判断Socket连接失效的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。