`
cuisuqiang
  • 浏览: 3935850 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
3feb66c0-2fb6-35ff-968a-5f5ec10ada43
Java研发技术指南
浏览量:3650477
社区版块
存档分类
最新评论

如何判断Socket连接失效

阅读更多

现在都搞升级,本人也也使用JDK6进行开发。在开发工程中对Socket进行管理时对于这个连接的超时和是否失效进行研究。结果网上的资料很是让人失望,可以说google和百度下来,前几页原创很少都是抄袭。

说正经的,对于连接超时和失效肯定会想到设置超时时间和判断连接是否可用。但是设置超时时间后起作用是在调用read方法的时候,如果只是设置了超时时间却没有调用read,那么就算服务端中断连接,客户端也是无法得知的。而且就算read异常,当前的连接仍然是有效的。

我们来看如下代码运行后再继续:

服务端:

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秒后中断连接:

 

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();
		}
	}
}

我们在写一个客户端进行实验:

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();
		}
	}
}

  

至于输出结果,虽然服务端已经中断连接,但是客户端一直输出下面内容:

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

 从连接对象的属性信息来看,连接似乎没有中断。但实际虽然内存对象可用,但是物理连接已经失效。所以和网上其他抄袭来抄袭去的说法一样,靠连接对象属性来判断连接的可用性是不可行的

大家会说那就判断调用read方法是否报错呗。我之前有文章已经讨论了关于调用网络里面流的一些内容,在没有判断这个流可用之前,我们是不会调用read方法的,当然具体你是怎么做的我不知道我在说我的情况!

读取网络数据流时的那个方法是这样的:

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方法,那这个程序可真的够扯淡的了。

其实只要在使用这个连接的时候判断这个连接的可用性就行了,不要等着什么超时。

判断连接可用虽然网上一大片,其实就是那么回事,手动发送心跳包。

socket.sendUrgentData(0xFF); // 发送心跳包

 乳沟你的连接已经中断,那么这个方法就会报错。

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

心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。 用来判断对方(设备,进程或其它网元)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线。用于检测TCP的异常断开。基本原因是服务器端不能有效的判断客户端是否在线,也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。 比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包。发包方:可以是客户也可以是服务端,看哪边实现方便合理,一般是客户端。服务器也可以定时发心跳下去。一般来说,出于效率的考虑,是由客户端主动向服务器端发包,而不是服务器向客户端发。客户端每隔一段时间发一个包,使用TCP的,用send发,使用UDP的,用sendto发,服务器收到后,就知道当前客户端还处于“活着”的状态,否则,如果隔一定时间未收到这样的包,则服务器认为客户端已经断开,进行相应的客户端断开逻辑处理!

当然不能单纯理解心跳包就是往对方放松数据,因为心跳包是用于状态验证的,不是真实的数据。

我们来看如下例子,服务端不变:

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.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)

 那就是说,只要你的服务端断了,调用方法就会出错!

至于我说的他不会作为可见的数据你可以更改服务端代码打印客户端内容,你会发现服务端不会将心跳包内容展示给你!

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。为什么?因为我说的是对的!

哥通过示例说问题,也许不对有纰漏,但是咱绝对不去Copy,因为咱已经看厌了Copy!

 

请您到ITEYE看我的原创:http://cuisuqiang.iteye.com

或支持我的个人博客,地址:http://www.javacui.com

 

14
0
分享到:
评论
16 楼 DEMONU 2015-05-14  
虽然发送0xFF不会展示,但是听说会造成发送的数据混乱,楼主遇到过没
15 楼 cuisuqiang 2013-07-15  
forGG 写道
直接用开源框架啊,mima啊什么的里面已经做好心跳了

我现在用的就是mina
14 楼 forGG 2013-07-15  
直接用开源框架啊,mima啊什么的里面已经做好心跳了
13 楼 ikrboy 2012-11-22  
其实让我比较困扰的问题就是,我客户端没有断开socket,而是网络出现了问题,而服务器端检测不出socket断开了,就没有强制关掉socket,让客户端以为还是处于连接状态。socket编程真是一门大学问。
12 楼 ikrboy 2012-11-22  
cuisuqiang 写道
ikrboy 写道
楼主你好,请问可以用在服务器端验证client是否断开的情况吗?谢谢

如果是程序断开的或者是转换器主动断开的话,心跳包完全可以检测到,read方法也会报错连接异常!
但是如果是网线中断的话,目前没有发现有效检测方法,我的做法是如果检测到同一个IP下同一个端口的连接,服务端则标记之前处理这个连接的线程主动退出,然后缓存中记录处理该连接的线程为新的线程!
老线程在一段时间后会报错,然后退出,即使不是因为报错退出,因为已经标记他失效,所以他仍然会退出!
不知道这样解释是否满意,欢迎继续讨论!

解释的很详细,我回去慢慢研究,socket编程我还很差,谢谢您的耐心回答。
11 楼 cuisuqiang 2012-11-20  
ikrboy 写道
楼主你好,请问可以用在服务器端验证client是否断开的情况吗?谢谢

如果是程序断开的或者是转换器主动断开的话,心跳包完全可以检测到,read方法也会报错连接异常!
但是如果是网线中断的话,目前没有发现有效检测方法,我的做法是如果检测到同一个IP下同一个端口的连接,服务端则标记之前处理这个连接的线程主动退出,然后缓存中记录处理该连接的线程为新的线程!
老线程在一段时间后会报错,然后退出,即使不是因为报错退出,因为已经标记他失效,所以他仍然会退出!
不知道这样解释是否满意,欢迎继续讨论!
10 楼 ikrboy 2012-11-19  
楼主你好,请问可以用在服务器端验证client是否断开的情况吗?谢谢
9 楼 cuisuqiang 2012-10-14  
Njaubo 写道
楼主你好 我在客户端用sendUrgentData来测试服务器是否断开。服务器端是一直连接上的,但是客户端在循环测试5次后sendUrgentData就报错了,也就是表示服务器端断开了
这是怎么回事呀

sendUrgentData只是不断发送心跳包来检测是否正常连接,但是不能保证你的连接一直正常!代码中socket.setSoTimeout(10);是设置连接的超时时间,看看是不是超时了!
8 楼 Njaubo 2012-10-14  
楼主你好 我在客户端用sendUrgentData来测试服务器是否断开。服务器端是一直连接上的,但是客户端在循环测试5次后sendUrgentData就报错了,也就是表示服务器端断开了
这是怎么回事呀
7 楼 cuisuqiang 2012-05-23  
chenhua_1984 写道
程序正常运行,网线拔掉,socket.sendUrgentData(0xFF)方法要等待大概3分钟才报错?请教楼主这个有没有办法让它立即报错???????

你好,请你参考http://cuisuqiang.iteye.com/blog/1489661,这是我自己写的一个Socket连接池管理器,希望对你有所帮助!
6 楼 chenhua_1984 2012-05-23  
程序正常运行,网线拔掉,socket.sendUrgentData(0xFF)方法要等待大概3分钟才报错?请教楼主这个有没有办法让它立即报错???????
5 楼 moyan03 2012-05-02  
cuisuqiang 写道
moyan03 写道
LZ讲的挺好的,我的那个发送了心跳了没有报错,但是卡在了读input那了。

就是说一直没有读到数据吧

是的,用的DataInputStream。
4 楼 cuisuqiang 2012-04-27  
moyan03 写道
LZ讲的挺好的,我的那个发送了心跳了没有报错,但是卡在了读input那了。

就是说一直没有读到数据吧
3 楼 moyan03 2012-04-27  
LZ讲的挺好的,我的那个发送了心跳了没有报错,但是卡在了读input那了。
2 楼 cuisuqiang 2012-04-26  
zhangzhikaixinya 写道
感谢分享!讲的很好

大家一起进步,欢迎提出批评
1 楼 zhangzhikaixinya 2012-04-26  
感谢分享!讲的很好

相关推荐

    如何在C语言中判断socket是否已经断开

    下面来介绍判断非阻塞SOCKET是否已经断开的几种方法: 注意要区分不同操作系统分别进行测试, 包括WINDOWS, LINUX和UNIX会各有不同。 在WINDOWS下比较简单,可以使用FD_CLOSE事件判断SOCKET是否已经断开 view ...

    golang实现基于channel的通用连接池详解

    * 链接的最大空闲时间,超时的链接将关闭丢弃,可避免空闲时链接自动失效问题 * 使用channel处理池中的链接,高效 何为通用? 连接池的实现不依赖具体的实例,而依赖某个接口,本文的连接池选用的是io.Closer接口,...

    俄罗斯方块2.0版 支持局域网联机对战 附带源码

    注意:加入游戏,断开连接这两个功能在执行时,是另开线程的,我故意让关闭按钮和拖曳客户端区域移动窗口功能失效,看上去像是程序当住了,其实没当住,因为此时拖曳标题栏还是能移动窗口,右键菜单也可以弹出,这个...

    俄罗斯方块 局域网 联机 录像 程序+源码

    3.加入游戏,断开连接这两个功能在执行时,是另开线程的,我故意让关闭按钮和拖曳客户端区域移动窗口功能失效,看上去像是程序当住了,其实没当住,因为此时拖曳标题栏还是能移动窗口,右键菜单也可以弹出,这个“当...

    PlusWell热备软件

    (1) socket,即套接字。你使用任何的网络硬件接口,只要它能够支持TCP/IP的通讯协议。这样的硬件包括:以太网、快速以网。 (2)串行口 在PlusWell Cluster容错软件配置中, 你应当配置有一个串行口通信路径。串口...

    基于javatcpsocket通信的拆包和装包源码-network_and_protocol:网络协议与Netty

    主要是为了防止已失效的连接请求报文段突然又传到了B,因而报文错乱问题 假定A发出的第一个连接请求报文段并没有丢失,而是在某些网络结点长时间滞留了,一直延迟到连接释放 以后的某个时间才到达B,本来这是一个早已...

    mysql数据库my.cnf配置文件

    # 当把table_open_cache设置为很大时,如果系统处理不了那么多文件描述符,那么就会出现客户端失效,连接不上 max_allowed_packet = 1000000000 # 接受的数据包大小;增加该变量的值十分安全,这是因为仅当需要时才...

    详解WebSocket跨域问题解决

    我们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。 项目中遇到javascript跨域问题,父页面和子页面要通信,并且父子页面跨域,怎么办? ...

    java面试题

    77.5. 设置session失效的时间 89 77.6. 设置MIME响应类型 89 77.7. 设置tomcat的默认访问页面 89 77.8. 设置tomcat管理用户 89 77.9. 附录 90 78. websphere 90 79. 常见异常 90 79.1. nullpointerexception 90 79.2...

    registry-server:注册服务器,订阅 rpc 服务或发布 rpc 服务

    znode是否使用Ephemeral类型,在session结束时自动删除(如果服务提供者真的挂了,那客户端就不会在robin调用服务时,使用该失效的服务,就不会重复报错) ###客户端 ####反射 客户端通过注册框架XXService rpc = ...

    vscode 远程调试python的方法

    本文介绍了vscode 远程调试python的方法,分享给大家,具有如下: 实验环境 远程服务器:京东云,1核2G,centos7.3 64bit 本地环境配置 安装vscode,实验用的版本是1.10.2 vscode配置python插件,实验用的python...

    应用服务器中间件技术要求.doc

    " " "支持多服务器群集部署、负载均衡、组件级的失效即时" " "恢复(Fail Over)。支持Web层的集群和EJB集群。应 " " "提供较大型系统集群应用案例。 " " "支持会话亲和。均衡负载策略支持简单轮转、加权轮转" " ...

    大数据开发技术.pdf

    在客户端与数据节点之间共享数据 3 管理 Datanode 结点的状态报告, 包括 Datanode 结点的健康状态报 告和其所在结点上数据块状态报告,以便能够及时处理失效的数据结 点。 NameNode 与 SecondaryNameNode 的区别与...

    易语言程序免安装版下载

    取节点值文本()”返回的文本会失效的BUG。 2. 修改高级表格支持库,解决在鼠标按下和抬起之间收到时钟周期事件的情况下,无法收到“被单击”事件的BUG。 3. 修改扩展界面支持库三,解决单击卷帘菜单后导致日期框不...

    入门学习Linux常用必会60个命令实例详解doc/txt

    文件为doc版,可自行转成txt,在手机上看挺好的。 本资源来自网络,如有纰漏还请告知,如觉得还不错,请留言告知后来人,谢谢!!!!! ...入门学习Linux常用必会60个命令实例详解 ...Linux提供了大量的命令,利用它...

Global site tag (gtag.js) - Google Analytics