十四、WebSocket
WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信,浏览器和服务器只需要完成一次握手, 两者之间就可以创建持久性的连接,并进行双向数据传输。
HTTP协议和WebSocket协议对比:
- HTTP是短连接,WebSocket是长连接
- HTTP通信是单向的,基于请求响应模式,WebSocket支持双向通信
- HTTP和WebSocket底层都是TCP连接
应用场景:视频弹幕、网页聊天、体育实况更新、股票基金报价实时更新。
1、入门案例
实现步骤:
-
直接使用websocket.html页面作为WebSocket客户端
html<html> <body class="gray-bg"> <div class="online"> <input id="text" type="text"> <button onclick="send()">发送消息</button> <button onclick="closeWebSocket()">关闭连接</button> <div id="message"></div> </div> <script th:inline="javascript"> let websocket = null; let host = document.location.host; let sid=getRandomIntInclusive(0,1000000) function getRandomIntInclusive(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; // 最小值和最大值都是包含的 } //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { //连接WebSocket节点 websocket = new WebSocket("ws://localhost:9091/ws/"+sid); } else { alert('浏览器不支持webSocket'); } //连接发生错误的回调方法 websocket.onerror = function () { setMessageInnerHTML("连接失败"); }; //连接成功建立的回调方法 websocket.onopen = function (event) { setMessageInnerHTML("连接成功"); }; //接收到消息的回调方法 websocket.onmessage = function (event) { let data = event.data; console.log("后端传递的数据:" + data); //将后端传递的数据渲染至页面 setMessageInnerHTML(data) }; //连接关闭的回调方法 websocket.onclose = function () { setMessageInnerHTML("已关闭"); }; //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { websocket.close(); }; //将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML+=innerHTML+'<br/>' }; //手动关闭连接 function closeWebSocket() { websocket.close(); }; //发送消息 function send() { let message = document.getElementById('text').value; websocket.send(message); setMessageInnerHTML("已向服务器发送内容:"+message+) }; </script> </body> </html>
-
导入WebSocket的maven坐标
xml<!-- SpringBoot Websocket --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
-
导入WebSocket服务端组件WebSocketServer, 用于和客户端通信
java//主要是将目前的类定义成一个websocket服务器端(就像Controller层), 注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端 @ServerEndpoint("/ws/{sid}") @Component @Slf4j public class WebSocketService { /** * 用来存放所有的webSocket连接 */ private static Map<String,Session> sessionMap=new HashMap<>(); /** * 连接建立成功调用的方法 * * @param session 会话 */ @OnOpen public void onOpen(Session session, @PathParam("sid")String sid) { System.out.println("客户端:"+sid+" 连接成功!"); sessionMap.put(sid,session); // 将当前连接加入到连接池中 } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, @PathParam("sid") String sid) { System.out.println("收到来自窗口:" + sid + "的信息:" + message); } /** * 连接关闭调用的方法 */ @OnClose public void onClose(@PathParam("sid") String sid) { log.info("窗口:" + sid + "关闭了连接"); sessionMap.remove(sid); // 移除连接池中的连接 } /** * 自定义消息推送、可群发 * * @param message 消息 */ public static void sendAllClient(String message) { System.out.println("推送消息到窗口,推送内容:" + message); // 遍历所有连接(获取到Map的全部vaue值,进行遍历) for (Session item : sessionMap.values()) { try { item.getBasicRemote().sendText(message); // 发送消息 }catch (Exception e){ e.printStackTrace(); } } } }
-
导入配置类WebSocketConfiguration, 注册WebSocket的服务端组件
java@Configuration public class WebSocketConfig { /** * 这个bean的注册,用于扫描带有@ServerEndpoint的注解成为websocket ,如果你使用外置的tomcat就不需要该配置文件 */ @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
-
导入定时任务类WebSocketTask, 定时向客户端推送数据
java@Component public class WebSocketTask { //将WebSocketService注入到WebSocketTask中 @Autowired private WebSocketService webSocketService; /** * 每5秒执行一次 */ @Scheduled(cron = "0/5 * * * * ? ") public void webSocketService(){ webSocketService.sendAllInfo("服务器定时推送消息: "+LocalDateTime.now()); } }