看到这个标题,预计非常多人会说用socket.isConnected()或者socket.isClosed()等方法来推断即可了,但其实这些方法都是訪问socket在内存驻留的状态,当socket和server端建立链接后,即使socket链接断掉了,调用上面的方法返回的仍然是链接时的状态,而不是socket的实时链接状态。以下给出样例证明这一点。



  server端:



  package com.csc.server;

  import java.net.*;

  /**

  * @description 从这里启动一个服务端监听某个port

  * @author csc

  */

  public class DstService {

  public static void main(String[] args) {

  try {

  // 启动监听port 30000

  ServerSocket ss = new ServerSocket(30000);

  // 没有连接这种方法就一直阻塞

  Socket s = ss.accept();

  // 将请求指定一个线程去运行

  new Thread(new DstServiceImpl(s)).start();

  } catch (Exception e) {

  e.printStackTrace();

  }

  }

  }

  这里我设置了启动新线程来管理建立的每个socket链接,此处我们设置收到链接后10秒端来链接。代码例如以下:

  package com.csc.server;

  import java.net.Socket;

  /**

  * @description 服务的启动的线程类

  * @author csc

  */

  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 > 10) {

  socket.close();

  System.out.println("服务端已经关闭链接!");

  break;

  }

  index++;

  Thread.sleep(1 * 1000);//程序睡眠1秒钟

  }

  } catch (Exception e) {

  e.printStackTrace();

  }

  }

  }

  以上是服务端代码,以下写一个client代码来測试:

  package com.csc.client;

  import java.net.*;

  /**

  * @description client打印链接状态

  * @author csc

  */

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

  }

  }

  }

  先执行服务端代码,再执行client代码,我们会在client代码的控制台看到例如以下信息:

  true

  false

  true

  false

  false

  ------------我是切割线------------

  从连接对象的属性信息来看,连接是没有中断,但实际链接已经在服务端建立链接10秒后断开了。

这说明了上述几个方法是不能实时推断出socket的链接状态,仅仅是socket驻留在内存的状态。事实上。此时假设调用流去读取信息的话。就会出现异常。

  事实上,想要推断socket是否仍是链接状态。仅仅要发一个心跳包即可了,例如以下一句代码:



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

  关于心跳包的理论能够去google一下。我给出点參考:心跳包就是在client和server间定时通知对方自己状态的一个自定义的命令字,依照一定的时间间隔发送,类似于心跳。所以叫做心跳包。 用来推断对方(设备。进程或其他网元)是否正常执行。採用定时发送简单的通讯包。假设在指定时间段内未收到对方响应,则推断对方已经离线。用于检測TCP的异常断开。基本原因是server端不能有效的推断client是否在线。也就是说。server无法区分client是长时间在空暇,还是已经掉线的情况。所谓的心跳包就是client定时发送简单的信息给server端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端。服务端收到后回复一个固定信息假设服务端几分钟内没有收到client信息则视client断开。
比方有些通信软件长时间不使用,要想知道它的状态是在线还是离线就须要心跳包,定时发包收包。发包方:能够是客户也能够是服务端,看哪边实现方便合理,通常是client。

server也能够定时发心跳下去。一般来说,出于效率的考虑。是由client主动向server端发包,而不是server向client发。client每隔一段时间发一个包,使用TCP的,用send发,使用UDP的,用sendto发,server收到后,就知道当前client还处于“活着”的状态,否则。假设隔一定时间未收到这种包,则server觉得client已经断开,进行对应的client断开逻辑处理。

  既然找到了方法,我们就在測试一下。服务端代码无需修改,client代码例如以下:



  package com.csc.client;

  import java.net.*;

  /**

  * @description client打印链接状态

  * @author csc

  */

  public class DstClient {

  public static void main(String[] args) {

  try {

  Socket socket = new Socket("127.0.0.1", 30000);

  socket.setKeepAlive(true);

  socket.setSoTimeout(10);

  while (true) {

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

  System.out.println("眼下是处于链接状态。");

  Thread.sleep(3 * 1000);//线程睡眠3秒

  }

  } catch (Exception e) {

  e.printStackTrace();

  }

  }

  }

  又一次执行client程序,看到控制台打印例如以下信息:

  眼下是处于链接状态!

  眼下是处于链接状态!

  眼下是处于链接状态!

  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) 这说明当运行“socket.sendUrgentData(0xFF);”这个语句时,socket链接断开了,运行失败抛出了异常。

  另外注意,心跳包仅仅是用来检測socket的链接状态。并不会作为socket链接的通信内容,这点应当注意。

比isConnected()更靠谱的的获取socket实时连接状态!的更多相关文章

  1. 让你在上司眼里“更靠谱”的六个建议

    "勇于创新"是职场一大谎言 晋升选择题 你有两个下属,你想从他们中挑一个升职,你觉得哪一个更适合? 员工A: 优点:奉行"80%的精力维护20%的重要客户"的原 ...

  2. 比反射更快!使用ASM获取class信息(ClassReader)

    比反射更快!使用ASM获取class信息(ClassReader) 通常我们想要在java运行时获取class的信息时,通常使用反射的方式来获取其中的属性,方法,注解等信息.通常是这样的: Class ...

  3. [VB.NET]调用API获取/设置键盘按键状态

    1.调用GetAsyncKeyState()获取指定按键的状态,GetActiveKey()检索指定范围内的按键状态 2.调用keybd_event()可合成一次击键事件,通常两次击键事件间需要设定时 ...

  4. 获取select标签选中状态 的label的值。

    <select name="procode" onchange="alert(this.options[this.selectedIndex].text)" ...

  5. iOS-OC根据时间戳获取距离现在的状态(刚刚,分钟前,今天,昨天)

     iOS-OC根据时间戳获取距离现在的状态(刚刚,分钟前,今天,昨天) 获取时间戳 - (NSString *)distanceTimeWithBeforeTime:(double)beTime { ...

  6. Android编程获取网络连接状态(3G/Wifi)及调用网络配置界面

    随着3G和Wifi的推广,越来越多的Android应用程序需要调用网络资源,检测网络连接状态也就成为网络应用程序所必备的功能. Android平台提供了ConnectivityManager  类,用 ...

  7. Android编程 获取网络连接状态 及调用网络配置界面

    获取网络连接状态 随着3G和Wifi的推广,越来越多的Android应用程序需要调用网络资源,检测网络连接状态也就成为网络应用程序所必备的功能. Android平台提供了ConnectivityMan ...

  8. Android编程获取网络连接状态及调用网络配置界面

    获取网络连接状态 随着3G和Wifi的推广,越来越多的Android应用程序需要调用网络资源,检测网络连接状态也就成为网络应用程序所必备的功能. Android平台提供了ConnectivityMan ...

  9. C# 获取电脑的网络连接状态

    判断连网的方法介绍 1. InternetGetConnectedState 此函数获取网络状态有延时,且对网卡伤害较大 MSDN官方自己推荐不建议使用,不管是连网状态下还是断网情况下,获取的网络状态 ...

随机推荐

  1. 大数据技术之_16_Scala学习_06_面向对象编程-高级+隐式转换和隐式值

    第八章 面向对象编程-高级8.1 静态属性和静态方法8.1.1 静态属性-提出问题8.1.2 基本介绍8.1.3 伴生对象的快速入门8.1.4 伴生对象的小结8.1.5 最佳实践-使用伴生对象解决小孩 ...

  2. 【搜索】魔板问题(BFS)

    [搜索]魔板问题 时间限制: 1 Sec  内存限制: 64 MB提交: 5  解决: 3[提交][状态][讨论版] 题目描述 据说能使持有者成为世界之主的上古神器隐藏在魔板空间,魔板由8个同样大小的 ...

  3. 【贪心】Codeforces Round #401 (Div. 2) D. Cloud of Hashtags

    从后向前枚举字符串,然后从左向右枚举位. 如果该串的某位比之前的串的该位小,那么将之前的那串截断. 如果该串的某位比之前的串的该位大,那么之前那串可以直接保留全长度. 具体看代码. #include& ...

  4. Redis核心解读

    http://www.wzxue.com/redis核心解读/

  5. Telnet环境变量

    转:http://www.cnpaf.net/Class/Telnet/200408/2.html 当前位置: 网站首页>>协议大全>>TELNET协议>> Tel ...

  6. RedisTemplate SerializationFailedException: Failed to deserialize payload 异常解决

    问题描述: 使用RedisTemplate(spring-data-redis )进行redis操作的封装 , 现有一个incr的key , 当调用incr后返回值一切正常, 当对此key进行get调 ...

  7. canvas如何兼容IE8

    大家都知道canvas是个非常好玩的东西,但是IE9以下的浏览器不支持,有时候业务需求必须用到canvas,且又要求兼容IE8浏览器,那怎么办呢? 1.添加对html5的支持:<!--[if I ...

  8. C/C++ Windows移植到Linux

    近期写了有关Socket的程序,需要从windows移植到linux.现把有用的东东收集整理记录下来. 1.头文件windows下winsock.h或winsock2.h:linux下netinet/ ...

  9. 13:在O(1)时间删除单链表节点

    题目:给定单项链表的头指针和一个节点指针.定义一个函数在O(1)时间删除该节点. 解析: 删除单向链表中的一个节点,常规做法是必须找到待删除节点的前一个节点才干实现.而这样做的时间复杂度是O(n).无 ...

  10. 后台SQL注入实例

    简要描述: 汉庭连锁酒店后台SQL注入,可绕过登陆限制进入后台,可脱库. 详细说明: 问题发生在这个站点.http://miaosha.htinns.com/ 标题内没有写具体信息.因为怕发布后被人入 ...