使用Websocket实现消息推送(心跳)

go melody 报 close 1009 (message too big) go  语言写的ws客户端连接 melody 向 服务器的melody发送base64图片数据时, 报close 1009 (message too big). 并自动断开连接.  通过代码看是服务器关闭的. 调试发现 最后在初始化时加上 m := *melody.New() m.Config.MaxMessageSize = 10000000 问题解决... 阅读详情
AI摘要

本文深入探讨了WebSocket协议中关于心跳机制的设计与实现细节,包括控制帧的定义、Ping与Pong帧的功能及其交互过程,并通过两个不同的Java库演示了心跳的具体实现方式。

0x00 心跳

本来以为写完了,结果最近和一个同事在讨论心跳的事情,这里再做一个补充。先说我的结论:

  • WebSocket协议已经设计了心跳,这个功能可以到达检测链接是否可用
  • 心跳是用来检测链接是否可用的,不一定支持携带数据,可要看具体实现
  • 如果非要心跳中带上复杂数据,那这个可作为应用层的一个功能自己去实现。

心跳逻辑

0x01 WebSocket协议的控制帧

上一篇的最后简单提到了心跳,下面是对websocket协议控制帧的描述:

5.5.  Control Frames

   Control frames are identified by opcodes where the most significant
   bit of the opcode is 1.  Currently defined opcodes for control frames
   include 0x8 (Close), 0x9 (Ping), and 0xA (Pong).  Opcodes 0xB-0xF are
   reserved for further control frames yet to be defined.

   Control frames are used to communicate state about the WebSocket.
   Control frames can be interjected in the middle of a fragmented
   message.

   All control frames MUST have a payload length of 125 bytes or less
   and MUST NOT be fragmented.
  • Ping的协议头是0x9,Pong的协议头是0xA
  • 控制帧最大载荷为125bytes且不能拆分

0x02 WebSocket协议的心跳

下面再来看看对心跳的规定:

5.5.2.  Ping

   The Ping frame contains an opcode of 0x9.

   A Ping frame MAY include "Application data".
   // 注:Ping帧中可能会携带数据

   Upon receipt of a Ping frame, an endpoint MUST send a Pong frame in
   response, unless it already received a Close frame.  It SHOULD
   respond with Pong frame as soon as is practical.  Pong frames are
   discussed in Section 5.5.3.
   // 注:在收到Ping帧后,端点必须发送Pong帧响应,除非已经收到了Close帧。在实际中应尽可能快的响应。

   An endpoint MAY send a Ping frame any time after the connection is
   established and before the connection is closed.

   NOTE: A Ping frame may serve either as a keepalive or as a means to
   verify that the remote endpoint is still responsive.

5.5.3.  Pong

   The Pong frame contains an opcode of 0xA.

   Section 5.5.2 details requirements that apply to both Ping and Pong
   frames.

   A Pong frame sent in response to a Ping frame must have identical
   "Application data" as found in the message body of the Ping frame
   being replied to.
   // 注:在响应Ping帧的的Pong帧中,必须携和被响应的Ping帧中相同的数据。

   If an endpoint receives a Ping frame and has not yet sent Pong
   frame(s) in response to previous Ping frame(s), the endpoint MAY
   elect to send a Pong frame for only the most recently processed Ping
   frame.

从上面的描述我们可以得到如下结论:

  • 心跳包中可能会携带数据
  • 当收到Ping帧的时候需要立即返回一个Pong帧
  • 在连接建立之后,随时都可以发送Ping帧
  • 心跳是用来测试链接是否存在和对方是否在线
  • 在响应Ping帧的的Pong帧中,必须携和被响应的Ping帧中相同的数据

0x03 测试

和之前一样,自己本地搭建的服务器,用的库是 org.java_websocket。
在其源码中我们可以找到这样一段:

package org.java_websocket;

public abstract class WebSocketAdapter implements WebSocketListener {
    ...

    public void onWebsocketPing(WebSocket conn, Framedata f) {
        FramedataImpl1 resp = new FramedataImpl1(f);
        resp.setOptcode(Opcode.PONG);
        conn.sendFrame(resp);
    }

    public void onWebsocketPong(WebSocket conn, Framedata f) {
    }

    ...
}

客户端也可以使用这个库,相同的逻辑,代码也是这一份。

然后我们再换一个库,com.squareup.okhttp3:okhttp-ws:3.4.2,他的实现如下:


package okhttp3.internal.ws;

public abstract class RealWebSocket implements WebSocket {
  ...
  public RealWebSocket(boolean isClient, BufferedSource source, BufferedSink sink, Random random,
      final Executor replyExecutor, final WebSocketListener listener, final String url) {
    this.listener = listener;

    writer = new WebSocketWriter(isClient, sink, random);
    reader = new WebSocketReader(isClient, source, new FrameCallback() {
      @Override public void onMessage(ResponseBody message) throws IOException {
        listener.onMessage(message);
      }

      @Override public void onPing(final Buffer buffer) {
        replyExecutor.execute(new NamedRunnable("OkHttp %s WebSocket Pong Reply", url) {
          @Override protected void execute() {
            try {
              writer.writePong(buffer);
            } catch (IOException ignored) {
            }
          }
        });
      }

      @Override public void onPong(Buffer buffer) {
        listener.onPong(buffer);
      }

      @Override public void onClose(final int code, final String reason) {
        readerSentClose = true;
        replyExecutor.execute(new NamedRunnable("OkHttp %s WebSocket Close Reply", url) {
          @Override protected void execute() {
            peerClose(code, reason);
          }
        });
      }
    });
  }
...
}

在处理Ping帧的时候,也是将协议字段改为Pong然后返回。

对心跳的测试代码已经上传到Github:ttdevs
WebSocketActivity.java
WebSocketOKActivity.java
SocketServer.java

在实际的测试中,可能会遇到一些异常,比如在我们自己的生产环境:当客户端发送带了简单数据的Ping帧后,服务器立马返回Pong帧,但是它会将携带的数据丢弃。这个就是服务端的问题了。

参考:

RFC6455: https://datatracker.ietf.org/doc/rfc6455/

服务端给客户端推送消息用Netty+WS实现 # 前言 曾几何时,不知道大家有没有在项目里遇到过需要服务端给客户端推送消息的需求,是否曾经苦恼过、纠结过,我们知道要想实现这样的需求肯定离不开websocket长连接方式,那么到底是该选原生的websocket还是更加高级的netty框架呢?在此我极力推荐netty,因为一款好的框架一般都是在原生的基础上进行包装成更好、更方便、更实用的东西,很多我们需要自己考虑的问题都基本可以不用去考虑... 阅读详情

相关推荐

通用接口开放平台设计与实现——(27)消息服务之心跳发送优化

前面我们说过,心跳策略是客户端来发送心跳,服务端响应心跳,客户端发现服务端未及时响应心跳时,认为通道异常,进行重连。客户端每隔固定时间频率向服务器端发送心跳,WebSocket协议约定的PingWebSocketFrame,服务端收到后马上会回复PongWebSocketFrame,如通道失效或服务端无响应情况下,就会触发客户端读空闲。心跳机制是保障长连接有效性的重要手段,我们原先的设计,是在客户端实现一个自定义的处理器。

学海无涯,行者无疆 1246

websockets.exceptions.ConnectionClosedError: no close frame received or sent

这个错误表明WebSocket连接在没有接收或发送关闭帧(close frame)的情况下被关闭了。WebSocket协议规定,连接的关闭应该是由发送关闭帧开始的,这样的机制允许双方进行干净的断开连接。当这个过程中断或不按预期发生时,就可能会看到这样的错误。这个错误可能由多种原因触发,包括网络问题、服务端或客户端的异常关闭等。# 使用WebSocket连接。# 连接结束,发送关闭帧。

weixin_53704902的博客 5330

tiktok算法协议研究

经过上述分析,可以确定目标字符串来源于一段 JSON 数据,而这段 JSON 数据来自于一个经过加密的本地文件。对字符串 "sdi_v2" 进行 SHA-1 计算,得到 20 字节的结果;将第一步得到的数据进行MD5计算,生成16字节的结果;将第二步的结果转换为十六进制字符串,从而得到 32 字节的密钥。写这种算法分析的帖子真的是太无聊了,就先分析到这里吧,后续有机会再来谈下被加密的本地文件是怎么来的!!自我感觉TT的算法并不难,就是量太大了,所以我想问问有没有感兴趣的朋友来一起分析,欢迎联系。

2503_90751938的博客 2582

websocket创建客户端的两种方式及区别

需要创建一个ws客户端mock弹幕一直给直播间发送消息。于是使用了async with websockets.connect(uri) as websocket 创建的ws客户端发送消息。但是发现发送一会儿后,客户端就自动关闭了,曝出:“websockets.ConnectionClosedError, WebSocket连接关闭: no close frame received or sent”即:websocket.connect(url) as websocket 返回的异步上下文管理器对象。

yuanfeidexin的博客 3146

蓝桥杯历年真题分类汇总(史上最全版本,一定不要错过)

天再高又怎样,踮起脚尖就更接近阳光。 满满的 题型总结​ 历年真题​ 视频讲解​ 比赛技巧 题型总结 2021 2020 2019 2018 2017 2016 2015 2014 2013 ...

m0_58367586的博客 11万+

遥感常用相关指数和计算方法(植被指数/水体指数/雪和冰指数/矿物指数/地表温度指数/云和阴影指数/农业指数)

遥感常用相关指数和计算方法(植被指数/水体指数/雪和冰指数/矿物指数/地表温度指数/云和阴影指数/农业指数)

m0_64361769的博客 1万+

websocket 消息丢失_Android中 使用 WebSocket 实现消息通信

前言消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送、信鸽推送等,但是对于消息聊天这种及时性有要求的或者三方推送不满足业务需求的,我们就需要使用WebSocket实现消息推送功能基本流程WebSocket是什么,这里就不做介绍了,我们这里使用的开源框架是https://github.com/TakahikoKawasaki/nv-...

weixin_39915204的博客 1385

第四章:无感FOC的平滑启动艺术:告别“咔哒”声与抖动

无感FOC启动技术面临"先有位置还是先有旋转"的核心矛盾,导致常见故障包括位置失准、负载突变等。基础方案采用开环I/F控制,但存在重载启动困难等局限性。进阶方案结合IPD位置检测技术,通过脉冲电压注入法精准定位转子初始位置。关键技术在于开环到闭环的平滑切换,采用混合观测器设计和相位对齐技术。量产优化包括自适应参数整定和故障恢复机制,确保启动可靠性和一致性。该系统工程方案可有效解决启动抖动、异响等问题,提升用户体验。

汽车软件开发 748

Golang/Gin-WebSocket实现实时消息推送

Golang/Gin-WebSocket实现实时消息推送前言gorilla/websocket基础用法实现实时消息推送代码api补充说明 前言 WebSocket在 HTML5 游戏和网页消息推送都使用比较多。 WebSocket 是 HTML5 的重要特性,它实现了基于浏览器的远程socket,它使浏览器和服务器可以进行全双工通信。 目前Go中用的比较多的WebSocket包是gorilla/websocket,本文将介绍如何使用gorilla/websocket,在Gin框架下编写WebSocket实时

qq_42887507的博客 9214

Qt入门教程【基础控件篇】QLineEdit输入框

QLineEdit输入框

小鱼酱的博客 3263

PCL ICP算法实现点云精配准【2026最新版】

PCL1.14.1 及之前版本所实现的迭代最近点ICP算法。博客长期更新,本文最新更新时间为:2026年4月17日。

点云侠的博客 31万+

消息推送之Websocket

Websocket 是基于TCP的一种新的网络协议。允许在单个 TCP 连接上进行全双工通信。与传统的 HTTP 请求-响应模式不同,WebSocket 提供了持久的连接,服务器和客户端可以随时主动推送数据,无需反复建立连接,可以进行双向数据传输。客户端可以向服务器发送数据,服务器也可以向客户端发送消息。HTTP协议与WebSocket协议对比不同点HTTP是短连接,WebStocket是长连接。HTTP通信是单向的,WebSocket通信是持久双向的相同点二者的底层都是TCP连接HTTP 连接响应。

菜鸟的博客 1173

“华为杯”研究生数学建模竞赛2017年-【华为杯】B题:面向下一代光通信的 VCSEL 激光器仿真模型

得出以下主要结论:在相同的偏置电流条件下,随着温度的升高,带宽的峰值向。在相同的温度下,随着电流的增大,带宽的峰值越小且曲线由波峰形状。方案,包括可能的数学公式,不同温度和偏置电流下的带宽响应曲线,并与问题。线,得出以下主要结论:在相同的偏置电流条件下,随着温度的升高,带宽的峰。在相同的温度下,随着电流的增大,带宽的峰值越小且曲线由波峰形状逐渐变得。得的激光器特性曲线和模型中仿真得到的特性曲线,之后,可以将两组曲线的差。说明的是,由于数值优化算法的成功与否很大程度上依赖于初始参数的猜测,参。

getusushu的博客 99

websocket 有 超时时间吗_Android中 使用 WebSocket 实现消息通信

前言消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送、信鸽推送等,但是对于消息聊天这种及时性有要求的或者三方推送不满足业务需求的,我们就需要使用WebSocket实现消息推送功能基本流程WebSocket是什么,这里就不做介绍了,我们这里使用的开源框架是https://github.com/TakahikoKawasaki/nv-...

weixin_42316079的博客 5619

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

vue中使用websocket通信接收后台数据、实现消息实时通讯

前言: 项目首页有一个消息铃铛,展示对应的消息数量。项目通过新增系统通知实时接收消息数量。 1、直接上代码 export default { data() { return { badgeValue: 0, // 消息总条数 // websocket消息推送 ws: null, // websocket实例 wsUrl: "", // websocket连结url tt: null, heartCheck: null,

zhaosisi0922的博客 6971

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android中 使用 WebSocket 实现消息通信

前言 消息推送功能可以说移动APP不可缺少的功能之一,一般简单的推送我们可以使用第三方推送的SDK,比如极光推送、信鸽推送等,但是对于消息聊天这种及时性有要求的或者三方推送不满足业务需求的,我们就需要使用WebSocket实现消息推送功能。 基本流程 WebSocket是什么,这里就不做介绍了,我们这里使用的开源框架是https://github.com/TakahikoKawasaki/n...

黄林晴 9034

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

vue(element ui) 使用websocket及心跳检测

websocket连接及心跳检测

wangjie的博客 5537

vue+springboot之原生websocket长连接实现消息推送

vue+springboot+websocket之原生websocket长连接实现消息推送 最近公司需要新增消息通知的功能,首先想到通过websocket长连接实现,由于主要业务还在于服务端的主动推送所以本文重点也是如此。 相信在选择使用websocket实现类似功能的小伙伴肯定对它有一定的了解了,因此本文不在赘述。 ...

qq_36442061的博客 2732

【jeecg-boot】jeecg-boot实时数据推送-websocket的使用

本实例以改造的全局的消息推送为例

gwcgwcjava的专栏 6877

uni-app中websocket的使用 断开重连、心跳机制

前言 最近关于H5和APP的开发中使用到了webSocket,由于web/app有时候会出现网络不稳定或者服务端主动断开,这时候导致消息推送不了的情况,需要客户端进行重连。查阅资料后发现了一个心跳机制,也就是客户端间隔一段时间就向服务器发送一条消息,如果服务器收到消息就回复一条信息过来,如果一定时间内没有回复,则表示已经与服务器断开连接了,这个时候就需要进行重连。 被动断开则进行重连,主动断开的不重连。 说明:下图针对两个Tab项(Open Trades 和 Closed Trades),只希望在..

firstcode666的博客 6411

求求你别用轮询了!手把手教你封装WebSocket消息推送,告别轮询方式!

如何从零搭建WebSocket消息推送功能,提升前端实时互动体验。通过WebSocket管理模块的封装,不仅避免了频繁轮询对服务器的压力,还实现了心跳机制、消息推送、重连机制等功能

qq_41292756的博客 562

springboot+websocket双向通信实现消息推送功能

springboot+websocket双向通信实现消息推送功能 项目中如果需要假如消息推送功能,有时会用到websocket,这是一种长连接方式与服务器进行连接,优点:实时性较高,如果无数据更新时,并不会频繁进行请求,而只要数据进行更新,那么服务器就会想客户端发送请求,而这样的方式是以服务器资源作为代价来保证实时性。 前端代码 //webSocket对象 var websocket = nu...

非专业Bug开发工程师的博客 753
上一篇: Java中的比较: == 和 equals
下一篇: java.lang.NumberFormatException: Invalid float: "55,4" 分析
ttdevs
博客等级 码龄15年 388粉丝 91原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值