Springboot+WebSocket 自动重连机制

1、WebSocket

WebSocket 是一种在单个TCP连接上进行全双工通信的协议,通信协议可能更熟悉的是HTTP,因此,学习WebSocket可以-以- HTTP为参考点。

HTTP 协议的缺陷是通信只能由客户端发起,做不到服务器主动向客户端推送信息。

WebSocket 协议它的最大特点就是弥补了HTTP的缺陷,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于消息推送技术的一种。


需要注意的是:WebSocket 不能与Socket同论,因为Socket是一种接口而不是协议,即Socket是HTTP实现的一种接口。


因为WebSocket是一种协议,可以有很多种实现通信的方法,从不同编程语言到框架设计的不同。


以下将是配合Springboot以及一些工具包实现的一种案例,仅供参考。

2、案例

2.1、服务端

(项目初始化过程省略…)

2.1.1、依赖包

(相关版本号根据所处的年代自行更替)

      <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency><dependency><groupId>javax.websocket</groupId><artifactId>javax.websocket-api</artifactId><version>1.1</version></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.13.3</version></dependency>

2.1.2、启动类

添加注解@EnableWebSocket

@SpringBootApplication
@EnableWebSocket
public class WSServerApplication {public static void main(String[] args) {SpringApplication.run(WSServerApplication .class, args);}}

2.1.3、配置类

使springboot扫描@ServerEndpoint注解

/*** @Description: 配置类*/
@Configuration
public class WebSocketConfig {/*** ServerEndpointExporter 作用** 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint** @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

2.1.4、工具类

管理连接集合

public class WebSocketMapUtil {public static ConcurrentMap<String, MyWebSocketServer> webSocketMap = new ConcurrentHashMap<>();public static void put(String key, MyWebSocketServer myWebSocketServer) {webSocketMap.put(key, myWebSocketServer);}public static MyWebSocketServer get(String key) {return webSocketMap.get(key);}public static void remove(String key) {webSocketMap.remove(key);}public static Collection<MyWebSocketServer> getValues() {return webSocketMap.values();}
}

2.1.5、服务

@ServerEndpoint(value = "/myWebSocket")
@Component
public class MyWebSocketServer {private Logger logger = LoggerFactory.getLogger(MyWebSocketServer.class);private Session session;/***   * 连接建立后触发的方法*/@OnOpenpublic void onOpen(Session session) {this.session = session;logger.info("onOpen" + session.getId());WebSocketMapUtil.put(session.getId(), this);}/***   * 连接关闭后触发的方法*/@OnClosepublic void onClose() {//从map中删除WebSocketMapUtil.remove(session.getId());logger.info("====== onClose:" + session.getId() + " ======");}/***    * 接收到客户端消息时触发的方法*/@OnMessagepublic void onMessage(String params, Session session) throws Exception {//获取服务端到客户端的通道MyWebSocketServer myWebSocket = WebSocketMapUtil.get(session.getId());logger.info("收到来自" + session.getId() + "的消息" + params);String result = "收到来自" + session.getId() + "的消息" + params;//返回消息给WebSocket客户端myWebSocket.sendMessage(1, "成功!", result);}/***    * 发生错误时触发的方法*/@OnErrorpublic void onError(Session session, Throwable error) {logger.info(session.getId() + "连接发生错误" + error.getMessage());error.printStackTrace();}public void sendMessage(int status, String message, Object datas) throws IOException {JSONObject result = new JSONObject();result.put("status", status);result.put("message", message);result.put("datas", datas);this.session.getBasicRemote().sendText(result.toString());}}

2.2、客户端

(项目初始化过程省略…)

2.2.1、依赖包

     <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.13.3</version></dependency><dependency><groupId>org.java-websocket</groupId><artifactId>Java-WebSocket</artifactId><version>1.3.8</version></dependency>

2.2.2、启动类

@SpringBootApplication
public class ClientApplication {public static void main(String[] args) {SpringApplication.run(ClientApplication .class, args);}}

2.2.3、客户端管理器

/*** 客户端管理器*/
public abstract class ClientManager {private static Logger logger = LoggerFactory.getLogger(ClientManager.class);//服务端IPprivate String url;//所管理的WebSocketprivate MyWebsocketClient websocketClient = null;//定时器private Timer dogCheckTimer = null;public ClientManager(String url) {this.url = url;}/*** 连接服务器*/public void connecToServer() {this.createWebSocket();this.timerCheckWebSocket(); //定期检查websocketClient状态,关闭则创建}private void createWebSocket() {if (this.getWebsocketClient() != null) {this.getWebsocketClient().close();this.setWebsocketClient(null);}try {MyWebsocketClient client = new MyWebsocketClient(new URI(url), new Draft_6455(), new HashMap<>(), 300);this.setWebsocketClient(client);this.websocketClient.setManager(this);client.connectBlocking();} catch (Exception e) {logger.error("创建 websocket client 异常:{}", e);}}/**
**重连机制  定时检查连接
*/private void timerCheckWebSocket() {if (this.dogCheckTimer == null)this.dogCheckTimer = new Timer();this.dogCheckTimer.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {//websocketClient不为空if (ClientManager.this.getWebsocketClient() != null) {WebSocket.READYSTATE dogReadyState = ClientManager.this.getWebsocketClient().getReadyState();if (!dogReadyState.equals(WebSocket.READYSTATE.OPEN))try {ClientManager.this.createWebSocket();} catch (Exception e) {logger.error("重新创建 websocket client 失败:{}", e);}}}}, 5000L, 5000L);}public abstract void onOpen();public abstract void onMessage(String s);public abstract void onClose(int i, String s, boolean b);public abstract void onError(Exception e);/*** 发送字符串消息** @param message*/public void send(String message) {if (getWebsocketClient() != null)getWebsocketClient().send(message);}// getter and setterpublic String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public Timer getDogCheckTimer() {return dogCheckTimer;}public void setDogCheckTimer(Timer dogCheckTimer) {this.dogCheckTimer = dogCheckTimer;}public synchronized MyWebsocketClient getWebsocketClient() {return websocketClient;}public synchronized void setWebsocketClient(MyWebsocketClient websocketClient) {this.websocketClient = websocketClient;}
}

2.2.4、客户端

public class MyWebsocketClient extends WebSocketClient {private Logger logger = LoggerFactory.getLogger(MyWebsocketClient.class);private ClientManager manager;public MyWebsocketClient(URI serverUri) {super(serverUri);}public MyWebsocketClient(URI serverUri, Draft protocolDraft) {super(serverUri, protocolDraft);}public MyWebsocketClient(URI serverUri, Draft protocolDraft, Map<String, String> httpHeaders, int connectTimeout) {super(serverUri, protocolDraft, httpHeaders, connectTimeout);}@Overridepublic void onOpen(ServerHandshake serverHandshake) {getManager().onOpen();}@Overridepublic void onMessage(String s) {if (this.manager != null){manager.onMessage(s);}}@Overridepublic void onClose(int i, String s, boolean b) {if (this.manager != null){manager.onClose(i,s,b);}}@Overridepublic void onError(Exception e) {if (this.manager != null){manager.onError(e);}}public ClientManager getManager() {return manager;}public void setManager(ClientManager manager) {this.manager = manager;}
}

2.2.5、客户端实例

这里才是真正应用到的客户端,前面的管理器以及客户端是抽象出的一层。

public class TestReceiver extends ClientManager implements Runnable{private static Logger logger = LoggerFactory.getLogger(TestReceiver.class);public TestReceiver(String url) {super(url);}@Overridepublic void onOpen() {logger.info("=======客户端连接成功========");Scanner scanner = new Scanner(System.in);while (true) {System.out.println("请输入消息:");this.send(scanner.next());try {//延迟一秒Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}@Overridepublic void onMessage(String s) {logger.info("=======服务的返回的信息:====={}===",s);}@Overridepublic void onClose(int i, String s, boolean b) {logger.info("=======客户端连接关闭成功========");}@Overridepublic void onError(Exception e) {logger.error("=======客户端连接异常========");}@Overridepublic void run() {logger.info("客户端启动");this.connecToServer();}
}

2.2.6、运行

@Component
public class webSocketInit {private static Logger logger = LoggerFactory.getLogger(webSocketInit.class);//服务器地址;websocket是ws://private String uri = "ws://localhost:7000/myWebSocket";@PostConstructpublic void init(){new Thread(new TestReceiver(uri)).start();}}

3、效果

(当然这里的效果不是重点…,你可以套入各种对应的场景)


客户端自动重连。

Springboot+WebSocket 自动重连机制相关推荐

  1. js websocket自动重连机制(心跳后续)

    window.webSocket = {}; var heartCheck = {lockReconnect: false, //避免ws重复连接maxReconnectionDelay: 30 * ...

  2. jdbc mysql 自动重连_Mysql中JDBC如何完成自动重连机制的案例

    软件安装:装机软件必备包 SQL是Structured Query Language(结构化查询语言)的缩写.SQL是专为数据库而建立的操作命令集,是一种功能齐全的数据库语言.在使用它时,只需要发出& ...

  3. jdbc mysql 自动重连_JDBC实现Mysql自动重连机制的方法详解

    JDBC是Java程序连接和访问各种数据库的API,它可以提供Java程序和各种数据库之间的连接服务,下面是爱站技术频道小编为大家带来的JDBC实现Mysql自动重连机制的方法详解. 日志:using ...

  4. macbook蓝牙pan未连接_蓝牙自动重连机制

    蓝牙自动重连机制的原理分析 在日常使用蓝牙的过程中,想必大家都发现了这样一个现象:连接蓝牙设备的手机在关闭再重新打开蓝牙后,会自动连接上先前连接着的那个设备,同样的场景对于安卓车机系统效果也是一致的. ...

  5. 开发手机蓝牙硬件APP如何实现蓝牙自动重连机制

    在日常使用蓝牙的过程中,想必大家都发现了这样一个现象:连接蓝牙设备的手机在关闭再重新打开蓝牙后,会自动连接上先前连接着的那个设备,同样的场景对于安卓手机系统效果也是一致的.那这是怎么实现的呢,本篇文章 ...

  6. Android 蓝牙开发——自动重连机制(十八)

    在日常使用蓝牙的过程中,想必大家都发现了这样一个现象:连接蓝牙设备的手机在关闭再重新打开蓝牙后,会自动连接上先前连接着的那个设备,同样的场景对于安卓车机系统效果也是一致的.本篇文章我们就来聊一聊安卓系 ...

  7. [Qt] TCP客户端与服务器断开连接自动重联机制

    TCP服务器断开连接自动重联机制 客户端加入定时器实现断线重联(客户端服务端代码见上一篇博客) 编译环境:Qt 5.9.5 ui界面如图: 代码如下 tcpclient.h #ifndef TCPCL ...

  8. 数据源自动重连机制设置

    一.场景 在网络状况不是非常良好,经常会出现暂时性的拥塞或者断开的情况,而且当我们重启数据库时也会发生类似的情况.所以需要配置中间件的连接池来实现连接测试以及自动重连,通过重新配置连接池,成功解决了这 ...

  9. java 心跳 断网重连_工作笔记5 - websocket心跳重连机制

    心跳重连缘由 在使用websocket过程中,可能会出现网络断开的情况,比如信号不好,或者网络临时性关闭,这时候websocket的连接已经断开, 而浏览器不会执行websocket 的?onclos ...

最新文章

  1. 论文阅读:Joint Learning of Single-image and Cross-image Representations for Person Re-identification
  2. h5常见问题汇总及解决方案
  3. Ubuntu16.04(64位)下安装和破解source insight4
  4. zabbix运行脚本监控ggsci报错
  5. python核心模块之pickle和cPickle讲解
  6. 2018年计算机应用基础性考,2018年电大计算机应用基础核心课形考册
  7. python计算多边形面积_Python求凸包及多边形面积教程
  8. mysql实战20 | 幻读是什么,幻读有什么问题?
  9. php曲线,PHP生成曲线图的函数
  10. 在Linux下判断系统当前是否开启了超线程
  11. Spark源码分析之一:Job提交运行总流程概述
  12. 【概率论】标准正态分布及概率表
  13. mac 外接键盘让 Home End 键生效
  14. cqyz oj | 【训练题】铲雪车问题
  15. 英语发音规则之26个字母发音规则(A字母)
  16. 时间“照妖镜”のmanic time
  17. turtle库画图单击鼠标获取坐标位置
  18. 邮件营销活动如何被病毒式传播?
  19. 服务器二手硬盘和新硬盘差距,过年换新拒绝被坑 教你辨别二手固态硬盘
  20. 技嘉b365m小雕驱动工具_百元也有“雕”牌!技嘉B365M Aorus Elite主板评测

热门文章

  1. 824c语言程序设计考研试题,2017年西藏大学文学院824计算机专业基础综合之C程序设计考研题库...
  2. 平均动能K输运方程的推导
  3. 谷歌地图地址地址自动完成框
  4. 浏览器搜索一个内容会跳转到空白网页的问题解决方案
  5. 基于讯飞接口的语音识别(python)
  6. 字符串的编码与构造、字符串格式化、字符串的截取、字符串常用函数、正则表达式
  7. ubuntu20.04编译imu_tk时所遇问题
  8. 系统级性能调优工具Perf成功移植到龙芯处理器
  9. 如何通过以太坊智能合约来进行众筹(ICO)
  10. Android SDK 1.0 Chn.