转自:https://blog.csdn.net/qq_23167527/article/details/54290726

跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。
   
在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。
    心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。
   
其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。
    在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。
    总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。

心跳检测步骤:
1 客户端每隔一个时间间隔发生一个探测包给服务器
2 客户端发包时启动一个超时定时器
3 服务器端接收到检测包,应该回应一个包
4 如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器
5 如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了

 
 
很多人会用boolean socketFlag = socket.isConnected()
&& socket.isClosed()来判断就行了,但事实上这些方法都是访问socket在内存驻留的状态,当socket和服务器端建立链接后,即使socket链接断掉了,调用上面的方法返回的仍然是链接时的状态,而不是socket的实时链接状态,所以这样心跳用这个不靠谱,下面给出例子证明这一点。
 

服务器端:

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

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

  1. package com.csc.server;
  2. import java.net.Socket;
  3. /**
  4. * @description 服务的启动的线程类
  5. * @author csc
  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 > 10) {
  18. socket.close();
  19. System.out.println("服务端已经关闭链接!");
  20. break;
  21. }
  22. index++;
  23. Thread.sleep(1 * 1000);//程序睡眠1秒钟
  24. }
  25. } catch (Exception e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. }

以上是服务端代码,下面写一个客户端代码来测试:

  1. package com.csc.client;
  2. import java.net.*;
  3. /**
  4. * @description 客户端打印链接状态
  5. * @author csc
  6. */
  7. public class DstClient {
  8. public static void main(String[] args) {
  9. try {
  10. Socket socket = new Socket("127.0.0.1", 30000);
  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. ------------我是分割线------------

从连接对象的属性信息来看,连接是没有中断,但实际链接已经在服务端建立链接10秒后断开了。这说明了上述几个方法是不能实时判断出socket的链接状态,只是socket驻留在内存的状态。其实,此时如果调用流去读取信息的话,就会出现异常。

其实,想要判断socket是否仍是链接状态,只要发一个心跳包就行了,如下一句代码:

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

关于心跳包的理论可以去google一下,我给出点参考:心跳包就是在客户端和服务器间定时通知对方自己状态的一个自己定义的命令字,按照一定的时间间隔发送,类似于心跳,所以叫做心跳包。

用来判断对方(设备,进程或其它网元)是否正常运行,采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经离线。用于检测TCP的异常断开。基本原因是服务器端不能有效的判断客户端是否在线,也就是说,服务器无法区分客户端是长时间在空闲,还是已经掉线的情况。所谓的心跳包就是客户端定时发送简单的信息给服务器端告诉它我还在而已。代码就是每隔几分钟发送一个固定信息给服务端,服务端收到后回复一个固定信息如果服务端几分钟内没有收到客户端信息则视客户端断开。

比如有些通信软件长时间不使用,要想知道它的状态是在线还是离线就需要心跳包,定时发包收包。发包方:可以是客户也可以是服务端,看哪边实现方便合理,一般是客户端。服务器也可以定时发心跳下去。一般来说,出于效率的考虑,是由客户端主动向服务器端发包,而不是服务器向客户端发。客户端每隔一段时间发一个包,使用TCP的,用send发,使用UDP的,用sendto发,服务器收到后,就知道当前客户端还处于“活着”的状态,否则,如果隔一定时间未收到这样的包,则服务器认为客户端已经断开,进行相应的客户端断开逻辑处理!

既然找到了方法,我们就在测试一下,服务端代码无需改动,客户端代码如下:

  1. package com.csc.client;
  2. import java.net.*;
  3. /**
  4. * @description 客户端打印链接状态
  5. * @author csc
  6. */
  7. public class DstClient {
  8. public static void main(String[] args) {
  9. try {
  10. Socket socket = new Socket("127.0.0.1", 30000);
  11. socket.setKeepAlive(true);
  12. socket.setSoTimeout(10);
  13. while (true) {
  14. socket.sendUrgentData(0xFF); // 发送心跳包
  15. System.out.println("目前处于链接状态!");
  16. Thread.sleep(3 * 1000);//线程睡眠3秒
  17. }
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. }

重新运行客户端程序,看到控制台打印如下信息:

服务端程序运行10秒后再当执行“socket.sendUrgentData(0xFF);”语句时,socket链接断开了,所以会抛出异常。
    另外注意,心跳包只是用来检测socket的链接状态,并不会作为socket链接的通信内容,这点应当注意。
    转载请注明出处:http://blog.csdn.net/caoshichao520326/article/details/8900446

Socket心跳包机制总结【转】的更多相关文章

  1. socket 心跳包机制

    心跳包的发送,通常有两种技术 方法1:应用层自己实现的心跳包  由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动 ...

  2. Socket心跳包机制【转】

    转自:https://blog.csdn.net/xuyuefei1988/article/details/8279812 心跳包的发送,通常有两种技术 方法1:应用层自己实现的心跳包 由应用程序自己 ...

  3. Socket心跳包机制

    心跳包的发送,通常有两种技术方法1:应用层自己实现的心跳包 由应用程序自己发送心跳包来检测连接是否正常,大致的方法是:服务器在一个 Timer事件中定时 向客户端发送一个短小精悍的数据包,然后启动一个 ...

  4. socket心跳包机制实践与理解

    实现Socket心跳包主要分为两大类,第一采用tcp自带的KeepAlive,第二是自定义心跳包,恰巧我在产品VICA中都使用过,下面就这两种心跳包机制谈谈个人的理解与感受. 首先第一种KeepAli ...

  5. Socket 心跳包机制总结

    跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着.事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一 ...

  6. TCP socket心跳包示例程序

    在做游戏开发时,经常需要在应用层实现自己的心跳机制,即定时发送一个自定义的结构体(心跳包),让对方知道自己还活着,以确保连接的有效性. 在TCP socket心跳机制中,心跳包可以由服务器发送给客户端 ...

  7. web socket 心跳包的实现方案

    web socket 心跳包的实现方案05/30/2010 现在网络环境错综复杂,socket心跳包是获得健康强壮的连接的有效解决方案,今天,我们就在web socket中实现心跳包方案,是的,尽管我 ...

  8. socket的心跳包机制

    网络中的接收和发送数据都是使用操作系统中的SOCKET进行实现.但是如果此套接字已经断开,那发送数据和接收数据的时候就一定会有问题.可是如何判断这个套接字是否还可以使用呢?这个就需要在系统中创建心跳机 ...

  9. TCP/UDP区别&&心跳包机制【转】

    转自:https://www.jianshu.com/p/6d93a3c21c34 UDP:用户数据报协议:主要用在实时性要求比较高的以及对质量相对较弱的地方.但是面对现在高质量的线路不会容易丢包,除 ...

随机推荐

  1. win7+opencv3.0.0+vs2010 安装及配置

    最近看<学习opencv>,想要跑人脸识别的例子,于是先配环境吧. 1.  opencv下载: 具体下载地址,http://opencv.org/,官网太慢,百度网盘的资源链接:http: ...

  2. spring mvc自定义注解--访问时验证

    作用:在访问controller的方法时,判断用户是否是登陆状态. step1:定义注解 import java.lang.annotation.ElementType; import java.la ...

  3. numpy 读取txt为array 一行搞定

    vec = np.genfromtxt('wiki.ch.text.vector', skip_header=1, delimiter=' ', dtype=None)skip_header=1是跳过 ...

  4. msgpack生成lib,vs新建lib等

    记录导师交给的任务 新建一个c++项目,运行老师的msgpack的cpp文件,然后会生成相应的lib,我做的东西需要调用到它(这是老师改写后的msgpack的lib) 我的任务是建一个静态库,将客户端 ...

  5. opencv图像识别技术在自动化测试中的应用

    在自动化测试中,基于xpath.js选择器.css选择器进行元素定位及判定的技术已经比较成熟.在实际应用中,无论是web端还是移动端,仍有很多时候需要根据页面内容.页面中的图像进行定位及判定,这里介绍 ...

  6. Linux命令(十二) 分割文件 split 合并文件 join

    一.分割文件 split 命令介绍 当处理文件时,有时需要将文件做分割处理,split 命令用于分割文件,可以分割文本文件,按指定的行数分割,每个分割后的文件都包含相同的行数.split 可以分割非文 ...

  7. emoji & click copy

    emoji & click copy document.execCommand("copy"); https://clipboardjs.com/ https://www. ...

  8. Vue---从后台获取数据vue-resource的使用方法

    作为前端人员,在开发过程中,我们大多数情况都需要从后台请求数据,那么在vue中怎样从后台获取数据呢?接下来,我简单介绍一下vue-resource的使用方法,希望对大家有帮助. 一.下载vue-res ...

  9. 【题解】FBI序列

    题目描述 两伙外星人策划在未来的XXXX年侵略地球,侵略前自然要交换信息咯,现在,作为全球保卫队队长,你截获了外星人用来交换信息的一段仅由“F”,“B”,“I”,“O”组成的序列.为了保卫地球和平,为 ...

  10. Berland and the Shortest Paths CodeForces - 1005F(最短路树)

    最短路树就是用bfs走一遍就可以了 d[v] = d[u] + 1 表示v是u的前驱边 然后遍历每个结点 存下它的前驱边 再用dfs遍历每个结点 依次取每个结点的某个前驱边即可 #include &l ...