转自: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. Linux内核分析第二周学习笔记

    linux内核分析第二周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  2. Scalable Object Detection using Deep Neural Networks译文

    原文:https://arxiv.org/abs/1312.2249

  3. 剑指offer:数组中出现次数超过一半的数

    题目描述: 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字.例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}.由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2 ...

  4. Xcode常见设置

    1.设置主题和字体大小

  5. [转帖] 常见的cmd命令

    记录一下 后期用的到. ------------ 1. Echo :显示当前ECHO的状态:ECHO ON 或者ECHO OFF .2. ECHO ON :ECHO状态设为ON,将显示命令行(如每行前 ...

  6. CentOS 下运行Docker 内执行 docker build 命令的简单方法

    1. 通过部分文档进行学习...主要知识来源 https://blog.csdn.net/shida_csdn/article/details/79812817 2. 下载 docker 的rpm包. ...

  7. SSM 关于service和dao的封装

    近期由于客户需求,所以我们整个小组开始开发java项目. 虽然很久以前也是系统学习过.不过干了这么多年 .net  ,有关java的早就扔了. 好了,废话不多说.我们看看SSM 关于service和d ...

  8. 【刷题】LOJ 2818 「eJOI2018」循环排序

    题目描述 本题译自 eJOI2018 Problem F「Cycle Sort」 给定一个长为 \(n\) 的数列 \(\{a_i\}\) ,你可以多次进行如下操作: 选定 \(k\) 个不同的下标 ...

  9. 【BZOJ1071】[SCOI2007]组队(神仙题)

    [BZOJ1071][SCOI2007]组队(神仙题) 题面 BZOJ 洛谷 题解 首先把式子整理一下,也就是\(A*h+B*v\le C+A*minH+B*minV\) 我们正常能够想到的做法是钦定 ...

  10. 解题:SDOI 2017 硬币游戏

    题面 板板的生成函数做法太神仙了,我跑了 朴素的做法是建立AC自动机变成图上的随机游走问题 来仔细考虑一下转移,把状态分成非结尾状态和结尾状态.在一个非结尾状态后补一个串是一定能到达目标串的,但是如果 ...