zoukankan      html  css  js  c++  java
  • 比isConnected()更靠谱的的获取socket实时连接状态!

    看到这个标题,预计非常多人会说用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链接的通信内容,这点应当注意。

  • 相关阅读:
    Flink Flow
    Excellent JD
    Storm Flow
    Fundmentals in Stream Computing
    SpringBoot
    Generic/Template Programming in Flink
    Talks on C/S
    Thrift-RPC client in Flume
    Aysnc-callback with future in distributed system
    Unity Shader入门教程(二)最基本的Diffuse和Normal样例
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7267115.html
Copyright © 2011-2022 走看看