做网站编辑要会什么,施工企业项目管理中心岗位职责,网业qq,公司网站开发费用放在什么科目介绍
Websocket是一种在单个TCP连接上进行全双工通信的协议。与传统的HTTP协议不同#xff0c;websocket允许客户端与服务器之间的双向通信#xff0c;可以在同一条连接上进行多次消息的快速传递。我之前在做一个线上刷题网站的时候#xff0c;需要设计一个社区讨论模块websocket允许客户端与服务器之间的双向通信可以在同一条连接上进行多次消息的快速传递。我之前在做一个线上刷题网站的时候需要设计一个社区讨论模块当有用户评论了我的动态内容或者回复了我的评论的时候我需要被通知那么这边我就使用了websocket来实现消息回复的实时通知功能。
Websocket协议
原理
它的工作原理大致分为以下这么几个部分
1.建立连接客户端在初次加载的时候通过HTTP向服务端发起建立websocket连接的请求服务端接收到之后同意连接那么服务端就会将HTTP连接升级到websocket连接。这里分为两步
握手请求客户端向服务端发送的HTTP请求包含关键性头部Connection:upgradeupgrade:websocket代表要求升级到websocket协议sec-websocket-key是基于base64编码生成的校验值用于服务端对请求进行校验。
握手响应服务端在接收到请求之后校验通过会生成101switching code返回代表升级协议成功同时还有sec-websocket-Accept代表请求校验的合法性。
2.数据传输建立连接成功之后双方就可以发送数据帧了数据帧的关键性字段包括有FIN代表这是最后一帧Opcode代表数据传输的格式文本帧/二进制帧等负载数据负载长度等等。
3.关闭连接客户端和服务端任何一方都可以关闭连接也可以是网络中断关闭连接。
4.心跳机制为了确保双方通信的活跃性客户端或者服务端可以随时向对方发送ping帧对方接收到之后返回一个pong帧。
5.安全性websocket可以运行在TLS协议上确保传输的安全性比如大家熟知的HTTPS就是HTTPTLS。
业务代码实现
这里我们将给出我们项目中使用websocket实现的消息回复实时通知的部分代码。
首先我们需要做一些配置我们要求前端请求中有一个erp项用于存放用户的openid方便我们用于作唯一标识来识别不同的用户。
Component
public class WebSocketServerConfig extends ServerEndpointConfig.Configurator {Overridepublic boolean checkOrigin(String originHeaderValue) {return true;}Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {MapString, ListString parameterMap request.getParameterMap();ListString erpList parameterMap.get(erp);if(!CollectionUtils.isEmpty(erpList)){sec.getUserProperties().put(erp, erpList.get(0));}}}
接着就是我们自定义websocket类的编写在这边我们将实现消息的推送、异常处理、客户端的连接与关闭的逻辑。首先是连接成功与关闭的逻辑 /*** 连接建立成功调用的方法*/OnOpenpublic void onOpen(Session session, EndpointConfig conf) throws IOException {//获取用户信息try {MapString, Object userProperties conf.getUserProperties();String erp (String) userProperties.get(erp);this.erp erp;this.session session;if (clients.containsKey(this.erp)) {clients.get(this.erp).session.close();clients.remove(this.erp);onlineCount.decrementAndGet();}clients.put(this.erp, this);onlineCount.incrementAndGet();log.info(有新连接加入{}当前在线人数为{}, erp, onlineCount.get());sendMessage(连接成功, this.session);if(offlineMessages.containsKey(this.erp)){ConcurrentLinkedQueueString messages offlineMessages.get(this.erp);while (!messages.isEmpty()){sendMessage(messages.poll(),this.session);}}} catch (Exception e) {log.error(建立链接错误{}, e.getMessage(), e);}}/*** 连接关闭调用的方法*/OnClosepublic void onClose() {try {if (clients.containsKey(erp)) {clients.get(erp).session.close();clients.remove(erp);onlineCount.decrementAndGet();offlineMessages.computeIfAbsent(erp, k - new ConcurrentLinkedQueue()).add(你不在的时候南师很想你哦!!!);}log.info(有一连接关闭{}当前在线人数为{}, this.erp, onlineCount.get());} catch (Exception e) {log.error(连接关闭错误错误原因{}, e.getMessage(), e);}}
在这边我们维护了一个map缓存存放某个用户断开连接期间其他用户发送的消息等到用户再次上线时推送这边我们目前是采用的缓存维护的方式后续会做一个优化考虑到如果该服务挂掉那么缓存里的数据就会丢失所以我们可以在这边对数据做一个持久化比如存储到数据库服务挂掉之后重启的时候去表中读取未推送的数据加载到缓存中这是需要优化的一个点当然也可以考虑将数据存到redis里面配合redis的数据持久化机制可以保证数据不会丢失但是需要考虑redis宕机的问题这些不是本文讨论的重点感兴趣的小伙伴可以根据可能出现的问题进行下一步思考。
然后是发送消息的逻辑包括用户在线离线发送和群发消息的逻辑
/*** 指定发送消息*/public void sendMessage(String message, Session session) {if(session!null){log.info(服务端给客户端[{}]发送消息{}, this.erp, message);try {session.getBasicRemote().sendText(message);} catch (IOException e) {log.error({}发送消息发生异常异常原因{}, this.erp, message);}}}public void sendMessage(String message, String toId) {offlineMessages.computeIfAbsent(toId, k - new ConcurrentLinkedQueue()).add(message);}/*** 群发消息*/public void sendMessage(String message) {for (Map.EntryString, ChickenSocket sessionEntry : clients.entrySet()) {String erp sessionEntry.getKey();ChickenSocket socket sessionEntry.getValue();Session session socket.session;log.info(服务端给客户端[{}]发送消息{}, erp, message);try {session.getBasicRemote().sendText(message);} catch (IOException e) {log.error({}发送消息发生异常异常原因{}, this.erp, message);}}}
总结
在这里我们探讨了websocket的工作原理以及它在我们项目中的具体应用。除了消息回复的实时通知它的应用也是非常广泛比如说实时更新(股票行情游戏数据更新)在线协作等等。相较于HTTP协议websocket的通信模式是双向通信模式而HTTP是请求响应模式并且HTTP每次请求都会带上大量的请求头websocket在建立连接之后只传输很少的头部信息。所以在不同的场景下我们考虑使用不同的协议简单场景下HTTP已经足够如果是双方消息通知或者实时推送的话可以考虑websocket协议。最后如果大家有什么想法欢迎讨论。