okhttp的WebSocket心跳实现原理

okhttp的WebSocket实现心跳包需要服务端新增协议吗

‌不需要。‌

OkHttp的WebSocket实现已经内置了心跳包机制,通过PING/PONG帧来维持连接保活。这意味着,OkHttp的WebSocket客户端和服务端在通信过程中,会自动发送PING/PONG帧来检测连接的活跃状态,无需服务端新增任何协议或特别处理。这种机制确保了即使在没有数据传输的情况下,连接也能保持活跃,防止因为长时间没有通信而导致连接被意外关闭。因此,使用OkHttp进行WebSocket通信时,服务端不需要做任何特别的处理来实现心跳包功能‌1。

此外,WebSocket协议本身已经设计了心跳机制,这个功能用于检测链接是否可用。虽然心跳功能不一定支持携带数据,具体实现可能会有所不同,但基本的心跳检测功能已经包含在WebSocket协议中,无需服务端额外实现‌

WebSocket协议 的PING/PONG机制

WebSocket 的 PING/PONG 是一种保持连接活跃的机制。当服务器需要检查客户端是否仍然在线,或者客户端需要检查服务器是否在线时,它们可以相互发送 PING 消息。对方需要回复 PONG 消息以证明自己在线。

PING 是一个控制帧,用于检测对端是否在线,PONG 是对 PING 的响应。PING 可以携带数据,PONG 必须不携带数据

okhttp的WebSocket添加心跳

首先,我来简单梳理一下okhttp中心跳的实现原理,如果只是想要解决方法的朋友可以直接跳过这一部分。

在okhttp中,实现心跳的方式非常简单,只需要在OkHttpClient创建时添加相应的配置即可:

c 复制代码
  OkHttpClient.Builder()
      .pingInterval(HEART_BEAT_RATE, TimeUnit.SECONDS)
      .build()

okhttp的WebSocket的心跳实现原理

c 复制代码
    //OkHttpClient.java
  @Override public WebSocket newWebSocket(Request request, WebSocketListener listener) {
    RealWebSocket webSocket = new RealWebSocket(request, listener, new Random(), pingInterval);
    webSocket.connect(this);
    return webSocket;
  }
c 复制代码
   //RealWebSocket.java
  public RealWebSocket(Request request, WebSocketListener listener, Random random,long pingIntervalMillis) {
    //...
    this.pingIntervalMillis = pingIntervalMillis;
        //...
  }

    public void initReaderAndWriter(String name, Streams streams) throws IOException {
    synchronized (this) {
      //...
      this.executor = new ScheduledThreadPoolExecutor(1, Util.threadFactory(name, false));
      if (pingIntervalMillis != 0) {
        executor.scheduleAtFixedRate(
            new PingRunnable(), pingIntervalMillis, pingIntervalMillis, MILLISECONDS);
      }
            //...
    }
  }

    private final class PingRunnable implements Runnable {
    @Override public void run() {
      writePingFrame();
    }
  }

    void writePingFrame() {
        //...
    try {
      writer.writePing(ByteString.EMPTY);
    } catch (IOException e) {
      failWebSocket(e, null);
    }
        //...
  }

    //WebSocketWriter.java
    void writePing(ByteString payload) throws IOException {
    writeControlFrame(OPCODE_CONTROL_PING, payload);
  }

上面的代码就是ping的主要发送逻辑了,简单总结一下就是如果pingInterval不为0,那就开启一个的循环任务,定时的去发送代表ping的ControlFrame。

其中值得一提的就是ControlFrame这个概念,在WebSocket中的frame分为两类,一类叫做MessageFrame,也就是平时客户端与服务端互相通信的部分。另一类叫做ControlFrame,其中包括CONTROL_PING,CONTROL_PONG,CONTROL_CLOSE,可以看出这一类更偏重与功能性的方面。具体为哪一类的Frame可以在Header中进行区分。

上面已经介绍了心跳的发送逻辑,那么下面就轮到接收的逻辑了,还是先来看看代码:

c 复制代码
    //RealWebSocket.java
    public void loopReader() throws IOException {
    while (receivedCloseCode == -1) {
      // This method call results in one or more onRead* methods being called on this thread.
      reader.processNextFrame();
    }
  }

    //WebSocketReader.java
    void processNextFrame() throws IOException {
    readHeader();
    if (isControlFrame) {
      readControlFrame();
    } else {
      readMessageFrame();
    }
  }

    private void readControlFrame() throws IOException {
        //...
    switch (opcode) {
      case OPCODE_CONTROL_PING:
        frameCallback.onReadPing(controlFrameBuffer.readByteString());
        break;
      case OPCODE_CONTROL_PONG:
        frameCallback.onReadPong(controlFrameBuffer.readByteString());
        break;
      case OPCODE_CONTROL_CLOSE:
        //...
      default:
        throw new ProtocolException("Unknown control opcode: " + toHexString(opcode));
    }
  }

可以看到,接收的部分逻辑也很简单,就是通过一个循环去读取,如果接收到了消息,那就先通过header确定frame的类型,然后再分类进行处理。

而且值得注意的是,上面代码中出现了一个frameCallback的对象,而这个对象是WebSocketReader.FrameCallback这个接口的实现,而里面的onReadPing和onReadPong就是我们之后能够做文章的地方了。

c 复制代码
    WebSocketReader.FrameCallback
    public interface FrameCallback {
    void onReadMessage(String text) throws IOException;
    void onReadMessage(ByteString bytes) throws IOException;
    void onReadPing(ByteString buffer);
    void onReadPong(ByteString buffer);
    void onReadClose(int code, String reason);
  }

okhttp的WebSocket的心跳超时会自动重连吗

‌OkHttp的WebSocket实现支持心跳超时自动重连。‌

OkHttp的WebSocket实现通过设置心跳间隔来检测连接状态。如果客户端在一段时间内没有收到服务器的响应,即心跳超时,它会认为连接断开,并触发断线重连机制。这个过程确保了与服务器的持续通信。

具体来说,OkHttp允许用户设置心跳间隔,例如,通过:[OkHttpClient.Builder].pingInterval()方法设置心跳间隔,这个方法允许用户指定心跳消息发送的频率。如果服务器在规定的时间内没有响应心跳消息,客户端会认为连接已断开,并尝试重新建立连接。这种机制对于保持长时间运行的WebSocket连接特别重要,因为它能够自动处理网络不稳定或临时中断的情况,从而保持应用的实时性和响应性。

此外,OkHttp还支持通过配置来设置重连间隔,例如,通过:[RxWebSocket]的配置来设置重连间隔,这为用户提供了更大的灵活性,可以根据应用的需求调整重连的策略。这种自动重连的功能对于提高应用的健壮性和用户体验非常重要,尤其是在网络条件不稳定的环境中‌。

相关内容:
为okhttp的WebSocket添加心跳回调

相关推荐
鸡吃丸子6 分钟前
常见的实时通信技术(轮询、sse、websocket、webhooks)
前端·websocket·状态模式
LaoZhangGong12317 分钟前
W5500使用ioLibrary库创建TCP客户端
网络·经验分享·stm32·网络协议·tcp/ip
天天爱吃肉82182 小时前
车载以太网驱动智能化:域控架构设计与开发实践
java·运维·网络协议·微服务
源码方舟3 小时前
【HTML5】【AJAX的几种封装方法详解】
ajax·okhttp·html5
敖云岚3 小时前
【前端三剑客】Ajax技术实现前端开发
ajax·okhttp
IP管家3 小时前
企业级IP代理解决方案:负载均衡与API接口集成实践
服务器·网络·数据库·网络协议·tcp/ip·容器·负载均衡
{⌐■_■}4 小时前
【gRPC】HTTP/2协议,HTTP/1.x中线头阻塞问题由来,及HTTP/2中的解决方案,RPC、Protobuf、HTTP/2 的关系及核心知识点汇总
网络·网络协议·计算机网络·http·rpc·golang
Clownseven4 小时前
[IP地址科普] 服务器公网IP、私网IP、弹性IP是什么?区别与应用场景详解
服务器·网络协议·tcp/ip
兴达易控4 小时前
ProfibusDP主站转modbusTCP网关与ABB电机保护器数据交互
网络协议
开***能6 小时前
降本增效双突破:Profinet转Modbus TCP助力包布机产能与稳定性双提升
数据库·网络协议·tcp/ip