java中如何实现WebSocket客户端断线重连

技术java中如何实现WebSocket客户端断线重连这篇文章给大家分享的是有关java中如何实现WebSocket客户端断线重连的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Maven依赖<

这篇文章给大家分享的是有关爪哇岛中如何实现WebSocket客户端断线重连的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

Maven依赖

相关性

groupIdorg.projectlombok/groupId

artifactIdlombok/artifactId

可选用户/可选用户

/依赖性

属国

groupIdcn.hutool/groupId

artifactIdhutool-all/artifactId

版本5 .5 .2/版本

/依赖性

属国

GroupIdog。Java-web套接字/GroupId

artifactIdJava-web套接字/artifactId

版本1 .5 .1/版本

/dependency

代码

不废话,上代码。

包装人工智能。桂吉。csdn。ws。客户;

进口cn。胡工具。核心。线。thread util

进口cn。胡工具。核心。乌提尔。StrateIL

导入lombok。外部。slf4j。slf4j

importorg.java_websocket .WebSocket

导入组织。Java _ web套接字。客户。WebSocket客户端;

导入组织。Java _ web套接字。框架化。帧数据;

导入组织。Java _ web套接字。握手。服务器握手;

导入javax。净。SSL。*;

导入Java。净。插座;

导入Java。净。uri

导入Java。尼奥。Bytebuffer

导入Java。保安。证明合格的证书异常;

导入Java。保安。证明合格的X509证书;

导入Java。乌提尔。并发。时间单位;

导入Java。乌提尔。并发。原子的。原子布尔;

importjav

a.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
 
/** @Author huyi @Date 2021/10/15 20:03 @Description: 重连websocket客户端 */
@Slf4j
public class ReConnectWebSocketClient {
  /** 字符串消息回调 */
  private Consumer<String> msgStr;
  /** 字节流消息回调 */
  private Consumer<ByteBuffer> msgByte;
  /** 异常回调 */
  private Consumer<Exception> error;
  /** 连接标识 */
  private String key;
  /** ws服务端连接 */
  private URI serverUri;
  /** 尝试重连标识 */
  private AtomicBoolean tryReconnect;
  /** 需要ping标识 */
  private AtomicBoolean needPing;
  /** websocket连接实体 */
  private WebSocketClient webSocketClient;
  /** 重连次数 */
  private AtomicInteger reConnectTimes;
  /** 连接结束标识 */
  private AtomicBoolean end;
  /** 连接后初始发送报文,这里也可以不需要,如果服务端主动断开连接,重连后可以继续推送报文的话。 */
  private String initReConnectReq;
  /** 结束回调 */
  private Consumer<String> endConsumer;
 
  public ReConnectWebSocketClient(
      URI serverUri,
      String key,
      Consumer<String> msgStr,
      Consumer<ByteBuffer> msgByte,
      Consumer<Exception> error) {
    this.msgStr = msgStr;
    this.msgByte = msgByte;
    this.error = error;
    this.key = key;
    this.serverUri = serverUri;
    this.tryReconnect = new AtomicBoolean(false);
    this.needPing = new AtomicBoolean(true);
    this.reConnectTimes = new AtomicInteger(0);
    this.end = new AtomicBoolean(false);
    this.endConsumer = this::close;
    init();
  }
 
  /** 初始化连接 */
  public void init() {
    // 创建连接
    createWebSocketClient();
    // ping线程
    circlePing();
  }
 
  private void needReconnect() throws Exception {
    ThreadUtil.sleep(10, TimeUnit.SECONDS);
    int cul = reConnectTimes.incrementAndGet();
    if (cul > 3) {
      close("real stop");
      throw new Exception("服务端断连,3次重连均失败");
    }
    log.warn("[{}]第[{}]次断开重连", key, cul);
    if (tryReconnect.get()) {
      log.error("[{}]第[{}]次断开重连结果 -> 连接正在重连,本次重连请求放弃", key, cul);
      needReconnect();
      return;
    }
    try {
      tryReconnect.set(true);
 
      if (webSocketClient.isOpen()) {
        log.warn("[{}]第[{}]次断开重连,关闭旧连接", key, cul);
        webSocketClient.closeConnection(2, "reconnect stop");
      }
      webSocketClient = null;
      createWebSocketClient();
      connect();
      if (StrUtil.hasBlank(initReConnectReq)) {
        send(initReConnectReq);
      }
    } catch (Exception exception) {
      log.error("[{}]第[{}]次断开重连结果 -> 连接正在重连,重连异常:[{}]", key, cul, exception.getMessage());
      needReconnect();
    } finally {
      tryReconnect.set(false);
    }
  }
 
  private void createWebSocketClient() {
    webSocketClient =
        new WebSocketClient(serverUri) {
          @Override
          public void onOpen(ServerHandshake serverHandshake) {
            log.info("[{}]ReConnectWebSocketClient [onOpen]连接成功{}", key, getRemoteSocketAddress());
            tryReconnect.set(false);
          }
 
          @Override
          public void onMessage(String text) {
            log.info("[{}]ReConnectWebSocketClient [onMessage]接收到服务端数据:text={}", key, text);
            msgStr.accept(text);
          }
 
          @Override
          public void onMessage(ByteBuffer bytes) {
            log.info("[{}]ReConnectWebSocketClient [onMessage]接收到服务端数据:bytes={}", key, bytes);
            msgByte.accept(bytes);
          }
 
          @Override
          public void onWebsocketPong(WebSocket conn, Framedata f) {
            log.info(
                "[{}]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode={}",
                key,
                f.getOpcode());
          }
 
          @Override
          public void onClose(int i, String s, boolean b) {
            log.info("[{}]ReConnectWebSocketClient [onClose]关闭,s={},b={}", key, s, b);
            if (StrUtil.hasBlank(s) || s.contains("https")) {
              if (end.get()) {
                return;
              }
              try {
                needReconnect();
              } catch (Exception exception) {
                endConsumer.accept("reconnect error");
                error.accept(exception);
              }
            }
          }
 
          @Override
          public void onError(Exception e) {
            log.info("[{}]ReConnectWebSocketClient [onError]异常,e={}", key, e);
            endConsumer.accept("error close");
            error.accept(e);
          }
        };
    if (serverUri.toString().contains("wss://")) {
      trustAllHosts(webSocketClient);
    }
  }
 
  public void circlePing() {
    new Thread(
            () -> {
              while (needPing.get()) {
                if (webSocketClient.isOpen()) {
                  webSocketClient.sendPing();
                }
                ThreadUtil.sleep(5, TimeUnit.SECONDS);
              }
              log.warn("[{}]Ping循环关闭", key);
            })
        .start();
  }
 
  /**
   * 连接
   *
   * @throws Exception 异常
   */
  public void connect() throws Exception {
    webSocketClient.connectBlocking(10, TimeUnit.SECONDS);
  }
 
  /**
   * 发送
   *
   * @param msg 消息
   * @throws Exception 异常
   */
  public void send(String msg) throws Exception {
    this.initReConnectReq = msg;
    if (webSocketClient.isOpen()) {
      webSocketClient.send(msg);
    }
  }
 
  /**
   * 关闭
   *
   * @param msg 关闭消息
   */
  public void close(String msg) {
    needPing.set(false);
    end.set(true);
    if (webSocketClient != null) {
      webSocketClient.closeConnection(3, msg);
    }
  }
 
  /**
   * 忽略证书
   *
   * @param client
   */
  public void trustAllHosts(WebSocketClient client) {
    TrustManager[] trustAllCerts =
        new TrustManager[] {
          new X509ExtendedTrustManager() {
 
            @Override
            public void checkClientTrusted(
                X509Certificate[] x509Certificates, String s, Socket socket)
                throws CertificateException {}
 
            @Override
            public void checkServerTrusted(
                X509Certificate[] x509Certificates, String s, Socket socket)
                throws CertificateException {}
 
            @Override
            public void checkClientTrusted(
                X509Certificate[] x509Certificates, String s, SSLEngine sslEngine)
                throws CertificateException {}
 
            @Override
            public void checkServerTrusted(
                X509Certificate[] x509Certificates, String s, SSLEngine sslEngine)
                throws CertificateException {}
 
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
                throws CertificateException {}
 
            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
                throws CertificateException {}
 
            @Override
            public X509Certificate[] getAcceptedIssuers() {
              return null;
            }
          }
        };
 
    try {
      SSLContext ssl = SSLContext.getInstance("SSL");
      ssl.init(null, trustAllCerts, new java.security.SecureRandom());
      SSLSocketFactory socketFactory = ssl.getSocketFactory();
      client.setSocketFactory(socketFactory);
    } catch (Exception e) {
      log.error("ReConnectWebSocketClient trustAllHosts 异常,e={0}", e);
    }
  }
}

代码说明:

1、参数的重连次数可以配置。

2、增加异步pingpong线程,一旦结束连接会自动关闭。

3、对字符串、字节流、异常都有回调措施。

测试代码方法

  public static void main(String[] args) throws Exception {
    ReConnectWebSocketClient client =
        new ReConnectWebSocketClient(
            new URI(String.format("wss://192.168.1.77:24009")),
            "test",
            // 字符串消息处理
            msg -> {
              // todo 字符串消息处理
              System.out.println("字符串消息:" + msg);
            },
            null,
            // 异常回调
            error -> {
              // todo 字符串消息处理
              System.out.println("异常:" + error.getMessage());
            });
    client.connect();
    client.send("haha");
  }

验证结果

16:08:54.468 [WebSocketConnectReadThread-12] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onOpen]连接成功/192.168.1.77:24009
16:08:54.475 [WebSocketConnectReadThread-12] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onMessage]接收到服务端数据:text=connect success from tcp4:192.168.6.63:11018!
字符串消息:connect success from tcp4:192.168.6.63:11018!
16:08:56.080 [WebSocketConnectReadThread-12] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onClose]关闭,s=,b=true
16:09:06.097 [WebSocketConnectReadThread-12] WARN ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]第[1]次断开重连
16:09:06.150 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onOpen]连接成功/192.168.1.77:24009
16:09:06.150 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onMessage]接收到服务端数据:text=connect success from tcp4:192.168.6.63:11038!
字符串消息:connect success from tcp4:192.168.6.63:11038!
16:09:09.369 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:14.370 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:19.371 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:24.379 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:29.382 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:34.398 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:39.402 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:44.404 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:49.415 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:54.429 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:09:59.437 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:10:04.449 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:10:06.154 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:10:09.455 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:10:14.462 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:10:19.468 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onWebsocketPong]接收到服务端数据:opcode=PONG
16:10:19.644 [WebSocketConnectReadThread-16] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onClose]关闭,s=,b=true
16:10:29.654 [WebSocketConnectReadThread-16] WARN ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]第[2]次断开重连
16:10:31.710 [WebSocketConnectReadThread-19] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onError]异常,e={}
java.net.ConnectException: Connection refused: connect
 at java.net.DualStackPlainSocketImpl.connect0(Native Method)
 at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
 at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
 at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
 at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
 at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
 at java.net.Socket.connect(Socket.java:589)
 at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:673)
 at org.java_websocket.client.WebSocketClient.run(WebSocketClient.java:461)
 at java.lang.Thread.run(Thread.java:748)
16:10:31.710 [WebSocketConnectReadThread-19] INFO ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]ReConnectWebSocketClient [onClose]关闭,s=error close,b=false
异常:Connection refused: connect
16:10:34.473 [Thread-0] WARN ai.guiji.csdn.ws.client.ReConnectWebSocketClient - [test]Ping循环关闭

这里我才用的是手动关闭服务端方式触发,客户端被动断连情况。重连两次,第二次服务端还未启动导致异常触发。

感谢各位的阅读!关于“java中如何实现WebSocket客户端断线重连”这篇文章就分享到这里了,希望

内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/60905.html

(0)

相关推荐

  • oracle存储过程怎么创建日志表(oracle添加归档日志文件)

    技术Oracle日志组中如何添加冗余文件和日志组这篇文章将为大家详细讲解有关Oracle日志组中如何添加冗余文件和日志组,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。rac中需要指定t

    攻略 2021年12月17日
  • 三角形任意两边之和大于第三边,三角形的三边之间有怎样的关系

    技术三角形任意两边之和大于第三边,三角形的三边之间有怎样的关系1、三角形的三边关系:任意两边之和大于第三边三角形任意两边之和大于第三边,任意两边之差小于第三边。2、设三角形三边为a,b,c则a+b>c,a>c-b,b+c

    生活 2021年10月21日
  • 恩格斯名言,有关资本主义经济制度的名人名言

    技术恩格斯名言,有关资本主义经济制度的名人名言在资本主义生产的基础上恩格斯名言,历时较长范围较广的事业,要求在较长时间内预付较大量的货币资本。所以,这一类领域里的生产取决于单个资本家拥有的货币资本的界限。这个限制被信用制

    生活 2021年10月25日
  • XamarinAndroid组件中RecylerView适配器如何使用动画

    技术XamarinAndroid组件中RecylerView适配器如何使用动画这篇文章主要介绍XamarinAndroid组件中RecylerView适配器如何使用动画,文中介绍的非常详细,具有一定的参考价值,感兴趣的小

    攻略 2021年12月3日
  • 全国211大学,211里最好的15所大学

    技术全国211大学,211里最好的15所大学清华大学 502 6852 北京大学 502 684
    3 复旦大学 502 679
    4 上海交通大学 502 678
    5 复旦大学医学院 502 677
    6 北京大学医学部 5

    生活 2021年10月29日
  • 如何利用sql语句写入shell

    技术如何利用sql语句写入shell如何利用sql语句写入shell,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。目标ip:192.168.52.143一、

    攻略 2021年12月10日