http://cuisuqiang.iteye.com/blog/1453632

————————————————————————————————————————————————————————————————————

现在都搞升级,本人也也使用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!

如何判断Socket连接失效的更多相关文章

  1. java socket 判断Socket连接失效

    要判断socket连接链路是否可用时,不能通过socket.isClosed() 和 socket.isConnected() 方法判断,要通过心跳包 socket.sendUrgentData(0x ...

  2. 怎样实时判断socket连接状态?

    对端正常close socket,或者进程退出(正常退出或崩溃),对端系统正常关闭 这种情况下,协议栈会走正常的关闭状态转移,使用epoll的话,一般要判断如下几个情况 处理可读事件时,在循环read ...

  3. 判断socket连接是否失效

    http://blog.csdn.net/jazywoo123/article/details/8693661 http://www.itnose.net/st/141698-pn11.html

  4. JAVA 判断Socket 远程端是否断开连接

    最近在做项目的时候,遇到这样一个问题,如何判断 Socket 远程端连接是否关闭,如果关闭的话,就要重建连接Socket的类提供了一些已经封装好的方法, 如  isClosed().isConnect ...

  5. C#socket通信时,怎样判断socket双方是否断开连接

    我在Server端new了一个socket,然后bind,开了一个线程来accept前来连接的client,每接到一个client前来连接就新开一个线程和它进行通信.我把Server端得到的socke ...

  6. c#通过socket判断服务器连接是否正常

    判断Socket是否连接上,需要通过发包来确认. 之前确认都是调用调用socket的connected属性,然而该属性是上次的连接是否成功的结果,不及时. // 检查一个Socket是否可连接 pri ...

  7. socket通信时如何判断当前连接是否断开--select函数,心跳线程,QsocketNotifier监控socket

    client与server建立socket连接之后,如果突然关闭server,此时,如果不在客户端close(socket_fd),会有不好的影响: QsocketNotifier监控socket的槽 ...

  8. C# Socket连接 无法访问已释放的对象

    在进行Socket长连接时,若服务器或客户端出现异常时,另外一端对Socket对话进行操作时,程序会出现无法访问已释放的对象的问题.例如客户端出现问题主动断开Socket时,当服务器操作Socket时 ...

  9. hadoop单线程实现server多socket连接读取数据原理分析

    一.问题引出. Hadoop 的Server 采用了Java 的NIO,这样的话就仅需要为每一个socket 连接建立一个线程,读取socket 上的数据.在Server 中,只需要一个线程,就可以a ...

随机推荐

  1. 5个缺失的 JavaScript 数字格式化函数

    /** 下面两个函数都能对浮点数进行四舍五入,保留小数点后两位 **/ function CurrencyFormatted(amount) { var i = parseFloat(amount); ...

  2. C# Winform DataGridView分页功能的实现

    // 1.定义几个所需的公有成员: ; //每页显示行数 ; //总记录数 ; //页数=总记录数/每页显示行数 ; //当前页号 ; //当前记录行 DataSet ds = new DataSet ...

  3. js中encode、decode的应用说明

    escape 方法 返回一个可在所有计算机上读取的编码 String 对象. function escape(charString : String) : String 参数 charString 必 ...

  4. C#基本数据类型

    在第一章我们了解了C#的输入.输出语句后,我这一节主要是介绍C#的基础知识,本节的内容也是后续章节的基础,好的开端等于成功的一半.在你阅读完本章后,你就有足够的C#知识编写简单的程序了.但还不能使用继 ...

  5. Python GUI库

    PyQT不错的,只是要小心,这个东西是GPL的,如果你要写商业程序需要购买商业版授权.另外PyGTK.wxPython都是不错的GUI库.Python自带了一个基于TkInter的GUI库,如果你不想 ...

  6. HDU 3666 THE MATRIX PROBLEM (差分约束,最短路)

    题意: 给一个n*m矩阵,每个格子上有一个数字a[i][j],给定L和U,问:是否有这样两个序列{a1...an}和{b1...bn},满足 L<=a[i][j]*ai/bj<=U .若存 ...

  7. VPS的虚拟化技术—-XEN,KVM,OPENVZ

    市场上的VPS商家主要有 Xen ,KVM 和 OpenVZ 三种开源的虚拟化技术 Xen 是一个开放源代码虚拟机监视器,由剑桥大学开发.它打算在单个计算机上运行多达 100个满特征的操作系统.操作系 ...

  8. yii 打印sql

    $query = TableModel::find()->where([‘xxx’=>xxx]); var_dump($query->prepare(\Yii::$app->d ...

  9. ANDROID5.0触摸屏校准

    1.校准原理: 1)首先生成校准用的参数,可以适用tslib生成校准参数,也可以使用校准app生成:使用校准app进行校准对使用者要求比较低,使用者可以不用学习复杂的命令:本文使用app方式 2)生成 ...

  10. Windows下配置cygwin和ndk编译环境

    cygwin安装 正确的安装步骤其实很简单:1. 下载setup-86_64.exe 2. 直接从网上下载安装,选择包时,顶部选择“default”不变 3. 搜索make,勾选make,cmake, ...