如何判断Socket连接失效

如题所述

现在都搞升级,本人也也使用JDK6进行开发。在开发工程中对Socket进行管理时对于这个连接的超时和是否失效进行研究。结果网上的资料很是让人失望,可以说google和百度下来,前几页原创很少都是抄袭。
说正经的,对于连接超时和失效肯定会想到设置超时时间和判断连接是否可用。但是设置超时时间后起作用是在调用read方法的时候,如果只是设置了超时时间却没有调用read,那么就算服务端中断连接,客户端也是无法得知的。而且就算read异常,当前的连接仍然是有效的。
我们来看如下代码运行后再继续:
服务端:
[java] view plain copy print?
package com.service;
import java.net.*;
/**
* @说明 从这里启动一个服务端监听某个端口
* @author 崔素强
*/
public class DstService {
public static void main(String[] args) {
try {
// 启动监听端口 8001
ServerSocket ss = new ServerSocket(8001);
// 没有连接这个方法就一直堵塞
Socket s = ss.accept();
// 将请求指定一个线程去执行
new Thread(new DstServiceImpl(s)).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
然后我们来看执行类,执行类在收到连接5秒后中断连接:

[java] view plain copy print?
package com.service;
import java.net.Socket;
/**
* @说明 服务的具体执行类
* @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("服务端已经将连接关闭!");
break;
}
index++;
Thread.sleep(1 * 1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们在写一个客户端进行实验:
[java] view plain copy print?
package com.client;
import java.net.*;
/**
* @说明 服务的客户端,会请求连接并实时打印连接对象的一些信息,但是不会进行流的操作
* @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();
}
}
}

至于输出结果,虽然服务端已经中断连接,但是客户端一直输出下面内容:
[xml] view plain copy print?
true
false
true
false
false
------------------------
从连接对象的属性信息来看,连接似乎没有中断。但实际虽然内存对象可用,但是物理连接已经失效。所以和网上其他抄袭来抄袭去的说法一样,靠连接对象属性来判断连接的可用性是不可行的。
大家会说那就判断调用read方法是否报错呗。我之前有文章已经讨论了关于调用网络里面流的一些内容,在没有判断这个流可用之前,我们是不会调用read方法的,当然具体你是怎么做的我不知道我在说我的情况!
读取网络数据流时的那个方法是这样的:
[java] view plain copy print?
public static byte[] inputStreamToByte(InputStream inStream)
throws Exception {
int count = 0;
int haveCheck = 0;
// 如果在网络传输中数据没有完全传递,则方法返回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] view plain copy print?
socket.sendUrgentData(0xFF); // 发送心跳包
乳沟你的连接已经中断,那么这个方法就会报错。
至于什么是心跳包,直接上理论吧。
心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。 用来判断对方(设备,进程或其它网元)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线。用于检测TCP的异常断开。基本原因是服务器端不能有效的判断客户端是否在线,也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。 比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包。发包方:可以是客户也可以是服务端,看哪边实现方便合理,一般是客户端。服务器也可以定时发心跳下去。一般来说,出于效率的考虑,是由客户端主动向服务器端发包,而不是服务器向客户端发。客户端每隔一段时间发一个包,使用TCP的,用send发,使用UDP的,用sendto发,服务器收到后,就知道当前客户端还处于“活着”的状态,否则,如果隔一定时间未收到这样的包,则服务器认为客户端已经断开,进行相应的客户端断开逻辑处理!
当然不能单纯理解心跳包就是往对方放松数据,因为心跳包是用于状态验证的,不是真实的数据。
我们来看如下例子,服务端不变:
[java] view plain copy print?
package com.client;
import java.net.*;
/**
* @说明 服务的客户端,会请求连接并实时打印连接对象的一些信息,但是不会进行流的操作
* @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); // 发送心跳包
System.out.println("目前是正常的!");
Thread.sleep(3 * 1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
看到控制台的输出:
[java] view plain copy print?
目前是正常的!
目前是正常的!
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] view plain copy print?
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("****************************");
bt会一直是Null。为什么?因为我说的是对的!
温馨提示:内容为网友见解,仅供参考
第1个回答  2017-07-28
对于连接超时和失效肯定会想到设置超时时间和判断连接是否可用。但是设置超时时间后起作用是在调用read方法的时候,如果只是设置了超时时间却没有调用read,那么就算服务端中断连接,客户端也是无法得知的。而且就算read异常,当前的连接仍然是有效的。

如何判断Socket连接失效
1)在局域网内的SOCKET连接失效,会导致SOCKET抛出异常。通过捕获异常可以知道连接失效;2)在广域网或Internet上,连接失效时有可能不会导致SOCKET抛出异常,这个时候得靠通信双方的超时约定来判断了。比如,通信双方约定如果超过100秒都接收不到对方数据,那就算连接失效 ...

如何判断Socket连接失效
第一种客户端端口是固定的,这时候如果服务端已经跟客户端连接了,那么必然不能产生第二个连接,因为端口已经被占用。第二种客户端端口不固定,这种情况下可以在服务端建立一个IP池,每当客户端请求链接时,根据客户端IP,扫描IP池中是否已经存在了IP,如果存在,不给链接,如果不存在,链接,并添加IP到...

如何判断Socket连接失效
如果是同步套接字的时候。你可以在发送(或接收)后向主线程发送一个消息,通知现在套接字可用。或者专门设定一个标志位,比如intflag;0是空闲,1是正在发送,-1是正在接收。每次进行套接字操作前先设置标志,操作完成后释放标志。如果是异步套接字,只要判断该套接字是否刻度可写可以参考\/classic\/thre...

如何判断Socket连接失效
最好的办法就是你在socket之后,在connet的时候加一个if判断,如果链接失败,就printf相关错误信息

如何判断Socket连接失效
说正经的,对于连接超时和失效肯定会想到设置超时时间和判断连接是否可用。但是设置超时时间后起作用是在调用read方法的时候,如果只是设置了超时时间却没有调用read,那么就算服务端中断连接,客户端也是无法得知的。而且就算read异常,当前的连接仍然是有效的。我们来看如下代码运行后再继续:服务端:[java] ...

如何判断Socket连接失效
socket.isclosed

如何处理socket10054错误
1. 检查网络连接状态:Socket 10054错误可能是由于网络不稳定或连接超时导致的。因此,首先要检查客户端和服务器之间的网络连接是否正常。如果使用无线网络,尝试切换到有线网络或检查信号强度。如果是局域网内通信,确保服务器和客户端在同一网络环境下,且网络通畅。2. 检查服务器端设置:服务器可能由于...

什么情况下会造成unixsocket失效
文件系统权限问题、文件系统空间不足。1、文件系统权限问题:访问的路径没有适当的权限,Unixsocket会失效。2、文件系统空间不足:系统没有足够的可用空间来创建、使用Unixsocket,Unixsocket会失效。

socket长连接断网后会自动重连吗
如果过了超时时间,还读取不到数据或发送不了数据。就会返回connected time out错误。socket的链接函数会返回,会自动关闭链接。超时时间内,会有N次重试,一般是系统平台在管理。应用级的重连机制需要应用程序实现。对服务器端,监听类型的socket(服务类的socket),不管网络断不断,一直会有效。

网站建设问题 [请教高手] 如何判断某个连接地址是否还有效
实现方法:1、将网站连接全部入数据库;该库与网站的ASP共用;2、本地编写一个程序,定时或逐项检查库中连接是否有效 3、更改或删除经过检查无效的地址,因为库是共享的,所以网站也会同时删除无效连接 4、CGI判断方法:建个socket,发送http请求,HTTP头返回200就是OK,其他一切都不OK。

相似回答