Socket心跳包机制总结【转】

时间:2022-08-23 14:26:50

转自: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. }

重新运行客户端程序,看到控制台打印如下信息:Socket心跳包机制总结【转】

服务端程序运行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. iOS笔记———数据存储

    应用沙盒:应用文件系统的根目录,每个应用都有独自的沙盒相互:在xcode中可以用NSHomeDirectory()函数,打印当前应用的沙盒根路径. 应用程序包:包含了所有资源文件和执行文件; * Do ...

  2. Day2-python基础2

    本次学习内容 1.for循环 2.continue and break 3.while循环 4.运算符 5.数据类型 数字 字符串 列表 1.for循环 猜年龄的游戏完善下,只有三次机会 for i ...

  3. sql-按周输出每月的周日期范围

    --日期参数,此处可以建立存储过程,接收月份,计算月开始结束时间或者直接接受开始与结束时间 declare @begDate datetime = '2014-06-01' declare @endD ...

  4. hdu 4417 Super Mario/树套树

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 题意很简单,给定一个序列求一个区间 [L, R,]中小于等于H的元素的个数. 好像函数式线段树可 ...

  5. Mac OS X操作系统常见快捷键集锦

    Mac OS X操作系统常见快捷键集锦 启动时的快捷键 启动时按住 X 键 : 强制从 Mac OS X 启动(适用于那些在同一宗卷上安装了 Mac OS X 和 Mac OS 9 双系统的 Mac ...

  6. WPF之Treeview控件简单用法

    TreeView:表示显示在树结构中分层数据具有项目可展开和折叠的控件 TreeView 的内容是可以包含丰富内容的 TreeViewItem 控件,如 Button 和 Image 控件.TreeV ...

  7. springboot+maven整合spring security

    springboot+maven整合spring security已经做了两次了,然而还是不太熟悉,这里针对后台简单记录一下需要做哪些事情,具体的步骤怎么操作网上都有,不再赘述.1.pom.xml中添 ...

  8. citySelect省市区jQuery联动插件

    参考地址:http://blog.csdn.net/qq_33556185/article/details/50704446 参考地址:http://www.lanrenzhijia.com/jque ...

  9. Makefile shell subst $(1)

    MAKE_3_80_realpath    = $(shell $(top_srcdir)/scripts/realpath.sh '$(subst $(SQUOTE),\\$(SQUOTE),$(1 ...

  10. 20165228 预备作业3 Linux安装及学习

    (一)安装虚拟机 根据娄老师给的Ubuntu版本和安装教程,我曾遇到如下问题: Q1:首先遇到的问题是没有开启虚拟化 解决方法:在重启电脑时进入BIOS>Configuratio > In ...