You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python websocket-client包发送WebSocket原始二进制ping数据

Python websocket-client 发送自定义原始WebSocket帧方案

问题现象

  • 基于websocket-client Python包开发WebSocket客户端时,回传心跳报文阶段发现服务端下发的ping报文与本地回传报文的原始字节不一致,触发服务端主动断开连接。
  • 将WebsocketApp的enableTrace参数设为True后,抓取到的收发日志如下:
++Rcv raw: b'\x81\x0b{"type":6}\x1e'
++Rcv decoded: fin=1 opcode=1 data=b'{"type":6}\x1e'
++Sent raw: b'\x81\x8bbr\xa1\xe3\x19P\xd5\x9a\x12\x17\x83\xd9T\x0f\xbf'
++Sent decoded: fin=1 opcode=1 data=b'{"type":6}\x1e'
  • 预期发送的原始字节为 b'\x81\x0b{"type":6}\x1e',但库默认会自动对发送数据做编码处理,且每次发送相同字符串内容*'{"type":6}' + '\x1e'*时,实际输出的原始报文均不相同。
  • 原有问题代码如下:
if _message["type"] == 6: # 过滤type=6的消息,该值代表服务端下发的ping
    wsapp.send('{"type":6}' + '\x1e') # 回传pong消息,客户端发送type=6代表pong
  • 测试调用库提供的websocket.send_binary(binary_message)方法发送二进制消息,效果与普通send()方法完全一致,依然会触发自动编码逻辑。

根本原因

日志中发送与接收报文的字节差异、同内容每次发送报文不同的现象,来自WebSocket协议的默认规则:

  • 根据RFC 6455规范,客户端发往服务端的所有WebSocket帧必须对载荷做掩码处理,掩码键为每次随机生成的4字节值,因此相同载荷每次生成的原始帧字节必然不同。
  • 接收的服务端帧第二个字节为0x0b,代表载荷长度11字节、无掩码;本地默认发送的帧第二个字节为0x8b,最高位置1代表开启掩码,后续紧跟4字节随机掩码、再拼接异或处理后的载荷,这是库的默认合规实现。
  • 服务端断连的核心原因并非掩码本身:当前调用send()/send_binary()方法发送的是opcode为1(文本帧)或2(二进制帧)的标准封装帧,不符合当前服务端要求的自定义无掩码心跳帧格式,需要绕开库默认的帧封装逻辑。

实现方案

websocket-client暴露了底层socket发送接口,可以跳过自动帧封装、自动加掩码的逻辑,直接发送完整的自定义原始字节帧:

  1. 弃用send()、send_binary()这类上层发送方法,这类方法会自动完成WebSocket帧封装、添加客户端掩码。
  2. 调用连接实例的底层socket.send()方法,直接传入构造好的完整原始帧字节即可,参考实现:
if _message["type"] == 6:
    # 直接传入构造完成的原始帧字节,跳过库的协议层自动处理
    target_raw_frame = b'\x81\x0b{"type":6}\x1e'
    wsapp.sock.send(target_raw_frame)

注意:该方式完全绕过库的协议层校验逻辑,需要自行保证传入的字节符合WebSocket帧格式规范,否则会触发连接错误。标准WebSocket服务端会强制要求客户端发送的帧携带掩码,无掩码帧会被直接拒绝,该方案仅适用于自定义协议校验逻辑的私有服务端场景。

内容的提问来源于stack exchange,提问作者ermrz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 04:42:10