网站速成,做gif表情包网站,中国平面设计网,asp 网站建设教程目录 1 Websocket是什么2 Websocket可以做什么3 Springboot整合Websocket3.1 服务端3.2 客户端 1 Websocket是什么
WebSocket 是一种基于 TCP 协议的全双工通信协议#xff0c;可以在浏览器和服务器之间建立实时、双向的数据通信。可以用于在线聊天、在线游戏、实时数据展示等… 目录 1 Websocket是什么2 Websocket可以做什么3 Springboot整合Websocket3.1 服务端3.2 客户端 1 Websocket是什么
WebSocket 是一种基于 TCP 协议的全双工通信协议可以在浏览器和服务器之间建立实时、双向的数据通信。可以用于在线聊天、在线游戏、实时数据展示等场景。与传统的 HTTP 协议不同WebSocket 可以保持长连接实时传输数据避免了频繁的 HTTP 请求和响应节省了网络带宽和服务器资源提高了应用程序的性能和用户体验。
2 Websocket可以做什么
项目中大部分的请求都是前台主动发送给后台后台接收后返回数据给前台返回数据后这个连接就终止了。如果要实现实时通信通用的方式是采用 HTTP 协议
不断发送请求。但这种方式即浪费带宽HTTP HEAD 是比较大的又消耗服务器 CPU 占用没有信息也要接受请求。
websocket可以建立长连接实现双向通信客户端和服务端都可以主动的向对方发送消息。 例如 假设张三今天有个快递快到了但是张三忍耐不住就每隔十分钟给快递员或者快递站打电话询问快递到了没每次快递员就说还没到等到下午张三的快递到了但是快递员不知道哪个电话是张三的可不是只有张三打电话还有李四王五所以只能等张三打电话才能通知他你的快递到了。 而最好的情况是张三给快递员第一次打电话时说明自己的身份快递员记录下来让自己和快递员之间形成一对一的关系可以互相联系到。张三也不用再次给快递员打电话了快递到了快递员会主动联系张三通知他来取。 后者就是websocket模式在客户端断开WebSocket连接或Server端中断连接前不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量大的情况下极大的节省了网络带宽资源的消耗有明显的性能优势且客户端发送和接受消息是在同一个持久连接上发起实现了“真·长链接”实时性优势明显。
在项目中聊天功能也是类似的逻辑A发送了消息B立刻就要收到A和B都属于前台客户端不可能直接从一个前台不走服务器传输给另一个前台过程一定是前台 — 服务器 - 前台。那前台客户端B接收消息是被动的需要服务器主动发送消息请求这就用到了WebSocket。大体流程如下图
3 Springboot整合Websocket
3.1 服务端 添加依赖 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId
/dependency添加Websocket配置文件 Configuration
public class WebSocketConfig {/*** 注入ServerEndpointExporter* 这个bean会自动注册使用了ServerEndpoint注解声明的Websocket*/Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}Webscoket操作类 import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;Component
ServerEndpoint(/websocket/{userId}) // 接口路径 ws://localhost:9001/webSocket/userId;
public class WebSocket {private static final Logger log Logger.getLogger(WebSocket.class.getName());//与某个客户端的连接会话需要通过它来给客户端发送数据private Session session;/*** 用户ID*/private String userId;//concurrent包的线程安全Set用来存放每个客户端对应的MyWebSocket对象。//虽然Component默认是单例模式的但springboot还是会为每个websocket连接初始化一个bean所以可以用一个静态set保存起来。// 注底下WebSocket是当前类名private static CopyOnWriteArraySetWebSocket webSockets new CopyOnWriteArraySet();// 用来存在线连接用户信息private static ConcurrentHashMapString,Session sessionPool new ConcurrentHashMapString,Session();/*** 链接成功调用的方法*/OnOpenpublic void onOpen(Session session, PathParam(valueuserId)String userId) {try {this.session session;this.userId userId;webSockets.add(this);sessionPool.put(userId, session);log.info(【websocket消息】有新的连接总数为:webSockets.size());} catch (Exception e) {}}/*** 链接关闭调用的方法*/OnClosepublic void onClose() {try {webSockets.remove(this);sessionPool.remove(this.userId);log.info(【websocket消息】连接断开总数为:webSockets.size());} catch (Exception e) {}}/*** 收到客户端消息后调用的方法** param message*/OnMessagepublic void onMessage(String message) {log.info(【websocket消息】收到客户端消息:message);}/** 发送错误时的处理* param session* param error*/OnErrorpublic void onError(Session session, Throwable error) {log.log(WARNING,用户错误,原因:error.getMessage());error.printStackTrace();}/*** 下面为服务端向客户端发送消息*/// 此为广播消息public void sendAllMessage(String message) {log.info(【websocket消息】广播消息:message);for(WebSocket webSocket : webSockets) {try {if(webSocket.session.isOpen()) {webSocket.session.getAsyncRemote().sendText(message);}} catch (Exception e) {e.printStackTrace();}}}// 此为单点消息public void sendOneMessage(String userId, String message) {Session session sessionPool.get(userId);if (session ! nullsession.isOpen()) {try {log.info(【websocket消息】 单点消息:message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}// 此为单点消息(多人)public void sendMoreMessage(String[] userIds, String message) {for(String userId:userIds) {Session session sessionPool.get(userId);if (session ! nullsession.isOpen()) {try {log.info(【websocket消息】 单点消息:message);session.getAsyncRemote().sendText(message);} catch (Exception e) {e.printStackTrace();}}}}
}上面的操作类中有几个主要的点需要注意 ServerEndpoint注解注解的value属性为调用时路径。类似于RequestMapping()设置的路径。添加该注解才会被注册。OnOpen链接成功调用的方法。OnMessage客户端可以主动给服务端发送消息此方法接受数据并处理。OnError发送错误时的处理。 服务端主动向客户端发送消息 测试用例 Resource
private WebSocket webSocket;GetMapping(sendMessage)
public AjaxResult queryById(Validated NotNull Long id){//创建业务消息信息JSONObject obj new JSONObject();obj.put(msgId, 00000001);//消息idobj.put(msgTxt, 服务端-客户端发送消息);//消息内容//全体发送webSocket.sendAllMessage(obj.toJSONString());//单个用户发送 (userId为用户id)//webSocket.sendOneMessage(userId, obj.toJSONString());//多个用户发送 (userIds为多个用户id逗号‘,’分隔)//webSocket.sendMoreMessage(userIds, obj.toJSONString());return AjaxResult.success(执行成功);
}3.2 客户端
script
export default {name: index,data() {return {websock:null};},mounted() {//初始化websocketthis.initWebSocket()},destroyed: function () {//关闭连接this.websocketclose();},methods: {initWebSocket: function () { // 建立连接// WebSocket与普通的请求所用协议有所不同ws等同于httpwss等同于httpsvar userId user-001;var url ws://localhost:9001/websocket/ userId;this.websock new WebSocket(url);this.websock.onopen this.websocketonopen;this.websock.onerror this.websocketonerror;this.websock.onmessage this.websocketonmessage;this.websock.onclose this.websocketclose;},// 连接成功后调用websocketonopen: function () {console.log(WebSocket连接成功);},// 发生错误时调用websocketonerror: function (e) {console.log(WebSocket连接发生错误);},// 接收后端消息websocketonmessage: function (e) {console.log(eee,e)var data eval(( e.data )); },// 关闭连接时调用websocketclose: function (e) {console.log(connection closed ( e.code ));},//向后台发送消息sendMessage(){let params {id:00000,msg:前端消息测试}let a JSON.stringify(params);this.websock.send(a)},}
/scriptwebsockke中内置了连接、错误、接收消息、接收消息、关闭的回调下面自己定义的websocketonopen、websocketonmessage等方法的名字可以随便起但需要在初始化时赋值给websocket对应的属性。
属性事件处理回调函数描述onopenwebsocketonopen建立连接时触发onerrorwebsocketonerror通信发生错误时触发onmessagewebsocketonmessage客户端接收服务端消息时触发onclosewebsocketclose连接关闭触发send无不需要回调函数建议直接调用websocket的send方法
下面测试下完整流程 创建连接 ws同httpwss同https后面路径为服务段ServerEndpoint注解的值以此选择连接不同连接端。 前台客户端主动发送消息给服务端 调用websock.send()方法但消息的类型需要注意socket本质是传输字节流所以不能把任意类型的数据直接传入send方法限制类型如下 等接收到数据以后通过IO包装类都可以把数据还原。 服务端成功接收到消息 服务端主动向客户端发送消息 客户端成功接收 可以看到是一个请求长连接 绿色向上的箭头是客户端发送给服务端红色向下的箭头是服务端发送给客户端
上述测试的流程如下