日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何判断Socket连接失效

發(fā)布時間:2024/1/23 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何判断Socket连接失效 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在開發(fā)工程中對Socket進行管理時對于這個連接的超時和是否失效進行研究。

對于連接超時和失效肯定會想到設(shè)置超時時間和判斷連接是否可用。但是設(shè)置超時時間后起作用是在調(diào)用read方法的時候,如果只是設(shè)置了超時時間卻沒有調(diào)用read,那么就算服務(wù)端中斷連接,客戶端也是無法得知的。而且就算read異常,當(dāng)前的連接仍然是有效的。

我們來看如下代碼運行后再繼續(xù):

服務(wù)端:

package com.service; import java.net.*; /*** @說明 從這里啟動一個服務(wù)端監(jiān)聽某個端口*/ public class DstService {public static void main(String[] args) {try { // 啟動監(jiān)聽端口 8001ServerSocket ss = new ServerSocket(8001);// 沒有連接這個方法就一直堵塞Socket s = ss.accept();// 將請求指定一個線程去執(zhí)行new Thread(new DstServiceImpl(s)).start();} catch (Exception e) {e.printStackTrace();}} }


然后我們來看執(zhí)行類,執(zhí)行類在收到連接5秒后中斷連接:

package com.service; import java.net.Socket; /*** @說明 服務(wù)的具體執(zhí)行類* @author 崔素強*/ public class DstServiceImpl implements Runnable {Socket socket = null;public DstServiceImpl(Socket s) {this.socket = s;}public void run() {try {int index = 1;while (true) {// 5秒后中斷連接if (index > 5) {socket.close();System.out.println("服務(wù)端已經(jīng)將連接關(guān)閉!");break;}index++;Thread.sleep(1 * 1000);}} catch (Exception e) {e.printStackTrace();}} }


我們在寫一個客戶端進行實驗:

package com.client; import java.net.*; /*** @說明 服務(wù)的客戶端,會請求連接并實時打印連接對象的一些信息,但是不會進行流的操作* @author 崔素強*/ 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)容:

true
false
true
false
false
------------------------

從連接對象的屬性信息來看,連接似乎沒有中斷。但實際雖然內(nèi)存對象可用,但是物理連接已經(jīng)失效。所以和網(wǎng)上其他抄襲來抄襲去的說法一樣,靠連接對象屬性來判斷連接的可用性是不可行的。

大家會說那就判斷調(diào)用read方法是否報錯唄。關(guān)于調(diào)用網(wǎng)絡(luò)里面流的一些內(nèi)容,在沒有判斷這個流可用之前,我們是不會調(diào)用read方法的。

讀取網(wǎng)絡(luò)數(shù)據(jù)流時的那個方法是這樣的:

public static byte[] inputStreamToByte(InputStream inStream)throws Exception {int count = 0;int haveCheck = 0;// 如果在網(wǎng)絡(luò)傳輸中數(shù)據(jù)沒有完全傳遞,則方法返回0while (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的機會,你的程序就不會出問題。當(dāng)然如果程序一直不調(diào)用read方法,那這個程序可真的夠扯淡的了。

其實只要在使用這個連接的時候判斷這個連接的可用性就行了,不要等著什么超時。

判斷連接可用雖然網(wǎng)上一大片,其實就是那么回事,手動發(fā)送心跳包。

socket.sendUrgentData(0xFF); // 發(fā)送心跳包

如果你的連接已經(jīng)中斷,那么這個方法就會報錯。

至于什么是心跳包,直接上理論吧。

心跳包就是在客戶端和服務(wù)器間定時通知對方自己狀態(tài)的一個自己定義的命令字,按照一定的時間間隔發(fā)送,類似于心跳,所以叫做心跳包。 用來判斷對方(設(shè)備,進程或其它網(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ù)器認為客戶端已經(jīng)斷開,進行相應(yīng)的客戶端斷開邏輯處理!

當(dāng)然不能單純理解心跳包就是往對方放松數(shù)據(jù),因為心跳包是用于狀態(tài)驗證的,不是真實的數(shù)據(jù)。

我們來看如下例子,服務(wù)端不變:

package com.client; import java.net.*; /*** @說明 服務(wù)的客戶端,會請求連接并實時打印連接對象的一些信息,但是不會進行流的操作* @author 崔素強*/ 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); // 發(fā)送心跳包System.out.println("目前是正常的!");Thread.sleep(3 * 1000);}} catch (Exception e) {e.printStackTrace();}} }


?看到控制臺的輸出:

目前是正常的!
目前是正常的!

java.net.SocketException: Invalid argument: sendat 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)容展示給你!

InputStream ips = socket.getInputStream(); byte[] bt = inputStreamToByte(ips); if(null != bt)System.out.println(new String(bt)); elseSystem.out.println("Bt is null"); System.out.println("****************************");


bt會一直是Null


總結(jié)

以上是生活随笔為你收集整理的如何判断Socket连接失效的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。