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

当第一次连接成功后, socket.isClosed() ==false, socket.isConnected()==true,只有在自己端代码中显示调用socket.close()方法时,socket.isClosed() ==true。

而链路的不可用时,自己端的socket是不知道的,仍然是 socket.isClosed() ==false, socket.isConnected()==true。

要通过心跳包 socket.sendUrgentData(0xFF)  进行测验。

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

服务端:

  1. package com.service;
  2. import java.net.*;
  3. /**
  4. * @说明 从这里启动一个服务端监听某个端口
  5. * @author 崔素强
  6. */
  7. public class DstService {
  8. public static void main(String[] args) {
  9. try {
  10. // 启动监听端口 8001
  11. ServerSocket ss = new ServerSocket(8001);
  12. // 没有连接这个方法就一直堵塞
  13. Socket s = ss.accept();
  14. // 将请求指定一个线程去执行
  15. new Thread(new DstServiceImpl(s)).start();
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }

然后我们来看执行类,执行类在收到连接5秒后中断连接:

  1. package com.service;
  2. import java.net.Socket;
  3. /**
  4. * @说明 服务的具体执行类
  5. * @author 崔素强
  6. */
  7. public class DstServiceImpl implements Runnable {
  8. Socket socket = null;
  9. public DstServiceImpl(Socket s) {
  10. this.socket = s;
  11. }
  12. public void run() {
  13. try {
  14. int index = 1;
  15. while (true) {
  16. // 5秒后中断连接
  17. if (index > 5) {
  18. socket.close();
  19. System.out.println("服务端已经将连接关闭!");
  20. break;
  21. }
  22. index++;
  23. Thread.sleep(1 * 1000);
  24. }
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }

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

  1. package com.client;
  2. import java.net.*;
  3. /**
  4. * @说明 服务的客户端,会请求连接并实时打印连接对象的一些信息,但是不会进行流的操作
  5. * @author 崔素强
  6. */
  7. public class DstClient {
  8. public static void main(String[] args) {
  9. try {
  10. Socket socket = new Socket("127.0.0.1", 8001);
  11. socket.setKeepAlive(true);
  12. socket.setSoTimeout(10);
  13. while (true) {
  14. System.out.println(socket.isBound());
  15. System.out.println(socket.isClosed());
  16. System.out.println(socket.isConnected());
  17. System.out.println(socket.isInputShutdown());
  18. System.out.println(socket.isOutputShutdown());
  19. System.out.println("------------------------");
  20. Thread.sleep(3 * 1000);
  21. }
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. }
  26. }

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

  1. true
  2. false
  3. true
  4. false
  5. false
  6. ------------------------

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

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

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

  1. public static byte[] inputStreamToByte(InputStream inStream)
  2. throws Exception {
  3. int count = 0;
  4. int haveCheck = 0;
  5. // 如果在网络传输中数据没有完全传递,则方法返回0
  6. while (count == 0) {
  7. count = inStream.available();
  8. haveCheck++;
  9. if (haveCheck >= 50)
  10. return null;
  11. }
  12. byte[] b = new byte[count];
  13. inStream.read(b);
  14. return b;
  15. }

就是说我们不会直接调用read方法,而available方法在流没有完整和网络中断时都会返回0,不会报错。

就是说就算你设置超时时间设置保持连接这些东西,只要你没有调用read的机会,你的程序就不会出问题。当然如果程序一直不调用read方法,那这个程序可真的够扯淡的了。

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

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

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

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

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

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

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

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

  1. package com.client;
  2. import java.net.*;
  3. /**
  4. * @说明 服务的客户端,会请求连接并实时打印连接对象的一些信息,但是不会进行流的操作
  5. * @author 崔素强
  6. */
  7. public class DstClient {
  8. public static void main(String[] args) {
  9. try {
  10. Socket socket = new Socket("127.0.0.1", 8001);
  11. socket.setKeepAlive(true);
  12. socket.setSoTimeout(10);
  13. while (true) {
  14. socket.sendUrgentData(0xFF); // 发送心跳包
  15. System.out.println("目前是正常的!");
  16. Thread.sleep(3 * 1000);
  17. }
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }

看到控制台的输出:

  1. 目前是正常的!
  2. 目前是正常的!
  3. java.net.SocketException: Invalid argument: send
  4. at java.net.PlainSocketImpl.socketSendUrgentData(Native Method)
  5. at java.net.PlainSocketImpl.sendUrgentData(PlainSocketImpl.java:550)
  6. at java.net.Socket.sendUrgentData(Socket.java:928)
  7. at com.client.DstClient.main(DstClient.java:14)

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

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

  1. InputStream ips = socket.getInputStream();
  2. byte[] bt = inputStreamToByte(ips);
  3. if(null != bt)
  4. System.out.println(new String(bt));
  5. else
  6. System.out.println("Bt is null");
  7. System.out.println("****************************");

java socket 判断Socket连接失效的更多相关文章

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

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

  2. 如何判断Socket连接失效

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

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

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

  4. Java中使用Socket连接判断Inputstream结束,java tcp socket服务端,python tcp socket客户端

    最近在试着用java写一个socket的服务器,用python写一个socket的客户端来完成二者之间的通信,但是发现存在一个问题,服务器方面就卡在读取inputsream的地方不动了,导致后面的代码 ...

  5. JAVA网络编程Socket常见问题 【长连接专题】

    一. 网络程序运行过程中的常见异常及处理 第1个异常是 java.net.BindException:Address already in use: JVM_Bind. 该异常发生在服务器端进行new ...

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

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

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

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

  8. 【Java】简易Socket连接实现

    客户端: import java.io.*; import java.net.Socket; import java.text.SimpleDateFormat; import java.util.D ...

  9. java网络编程socket解析

    转载:http://www.blogjava.net/landon/archive/2013/07/02/401137.html Java网络编程精解笔记2:Socket详解 Socket用法详解 在 ...

随机推荐

  1. 前台js加密实例

    1.base64加密 一个字节一般由8位表示,base64加密就是把8位表示转为6为表示,余下2位添0表示,故有个特点不能充分利用空间. 资源下载:jquery.js,base64.js // `ut ...

  2. 如何通过 ClickBank 等类似虚拟平台进行在线销售并获得收益

    CLICKBANK在国内被广大赚友简称为CB,和淘金小站之前介绍过的PayDotCom一样,都是国外非常著名的CPS广告联盟.CLICKBANK成立于1998年,是全球四个最大的虚拟商品零售平台之一( ...

  3. Spring第一弹—-全面阐述Spring及轻重量级容器的划分

    Spring是什么? Spring是一个开源的控制反转(Inversion of Control ,IoC)和面向切面(AOP)的容器框架,它的主要目得是简化企业开发. IOC 控制反转 :   1 ...

  4. linxu系统压缩解压命令

    使用cat命令进行文件的纵向合并 两种文件的纵向合并方法 归档文件和归档技术 归档的目的 什么是归档 tar命令的功能 tar命令的常用选项 使用tar命令创建.查看及抽取归档文件 使用tar命令创建 ...

  5. PKU 3041 Asteroids 最小点覆盖(最大匹配模板题)

    题目大意:给你一个N*N的矩阵, 里面有K个星球, 我们可以让武器攻击矩阵的一行或者一列来使得这个星球被击碎, 现在问你最少需要几个这种武器才能把所有的星球击碎? 解题思路:关键是建模构图 把每一行当 ...

  6. javaWeb 使用线程池+队列解决"订单并发"问题

    解决方式:使用线程池+队列 项目基于Spring,如果不用spring需要自己把 ThreadPoolManager.java 改成单例模式 1.写一个Controller(Spring mvc) / ...

  7. iOS知识点整理

    1.宏定义 #define  #   ## a. 后面一个#是转成字符串 b. 后面## 是连接的作用 2. __attribute__ 常用的 __attribute__(( constructor ...

  8. 有关string stringbuff stringbuild 的区别

    string  stringbuff stringbuild的执行效率: stringbuild>stringbuff>string String类是不可变类,任何对String的改变都会 ...

  9. JS等比例缩放图片,限定最大宽度和最大高度

    JS等比例缩放图片,限定最大宽度和最大高度 JavaScript //图片按比例缩放 var flag=false; function DrawImage(ImgD,iwidth,iheight){ ...

  10. 屏幕变黑白-winhotkey

    下载了个windows hot key 的工具想看快捷键冲突 结果安装好之后屏幕变黑白了,变成辅助模式了.而且鼠标移动到哪都加蓝色框框  如果这个时候你带上耳机就能听到在朗读,这应该也是一种辅助模式 ...