WebSocket学习总结

it2026-01-30  4

【简介】

近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据。

首先,博主谈一下,Http协议缺陷:通信只能由客户端发起。这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就很麻烦。我们只能通过轮询的方式,每隔一段时间,就发出一个询问,获取服务器有无最新的信息。最典型的就是聊天室。轮询的效率低,且非常浪费资源。

现在来谈谈应时而生的WebSocket。WebSocket最大的特点就是:服务器可以主动的向客户端推送消息,客户端也可以主动向服务器发送信息。

WebSocket的特点:

建立在TCP协议上,服务器端的实现比较容易。与HTTP协议有着良好的兼容性,默认端口也是80和443,并且握手阶段采用HTTP协议。数据格式比较轻量,性能开销小,通信高效。可以发送文本以及二进制数据。没有同源限制,客户端可以与任意服务器通信。协议标识符位ws(如果加密则为wss),服务器网址就是URL。

【前后端连接的URL】

ws://localhost:8080/ctm02vmas/webSocket

【前端代码】

<%@ page language="java" pageEncoding="UTF-8" %> <!DOCTYPE html> <html> <head> <title>Java后端WebSocket的Tomcat实现</title> </head> <body> Welcome<br/><input id="text" type="text"/> <button onclick="send()">发送消息</button> <hr/> <button onclick="closeWebSocket()">关闭WebSocket连接</button> <hr/> <div id="message"></div> </body> <script type="text/javascript"> var websocket = null; //判断当前浏览器是否支持WebSocket if ('WebSocket' in window) { websocket = new WebSocket("ws://localhost:8080/websocket"); } else { alert('当前浏览器 Not support websocket') } //连接发生错误的回调方法 websocket.onerror = function () { setMessageInnerHTML("WebSocket连接发生错误"); }; //连接成功建立的回调方法 websocket.onopen = function () { setMessageInnerHTML("WebSocket连接成功"); } //接收到消息的回调方法 websocket.onmessage = function (event) { setMessageInnerHTML(event.data); } //连接关闭的回调方法 websocket.onclose = function () { setMessageInnerHTML("WebSocket连接关闭"); } //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。 window.onbeforeunload = function () { closeWebSocket(); } //将消息显示在网页上 function setMessageInnerHTML(innerHTML) { document.getElementById('message').innerHTML += innerHTML + '<br/>'; } //关闭WebSocket连接 function closeWebSocket() { websocket.close(); } //发送消息 function send() { var message = document.getElementById('text').value; websocket.send(message); } </script> </html>

【后端代码】 

import com.hikvision.starfish.core.json.JsonUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; @Component @ServerEndpoint(value = "/webSocket") public class WebSocketServer { Logger logger=LoggerFactory.getLogger(WebSocketServer.class); //记录当前在线连接数 private static int onlineCount=0; private static CopyOnWriteArraySet<WebSocketServer> webSocketSet=new CopyOnWriteArraySet<>(); private static ConcurrentHashMap<WebSocketServer,String> sessionWithIdMap=new ConcurrentHashMap<>(); private Session session; @OnOpen public void onOpen(Session session){ this.session=session; webSocketSet.add(this); addOnlineCount(); logger.info("====加入新连接session:{}!当前在线人数为:{}", this.session.getId(), getOnlineCount()); try { sendMessage(JsonUtil.toJson("连接成功")); } catch (IOException e) { logger.error("websocket IO异常"); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 //移除sessionWtihBuildingMap中对应的对象 sessionWithIdMap.remove(this); subOnlineCount(); //在线数减1 logger.info("====关闭连接session:{}!当前在线人数为:{}", this.session.getId(), getOnlineCount()); } /** * 收到客户端消息后调用的方法 * * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message, Session session) throws Exception { logger.debug("====来自客户端的消息session:{}---message:{}", session.getId(), message); this.session = session; //保存session和对应的id sessionWithIdMap.put(this, message); sendMessage(JsonUtil.toJson("pong=>" + message)); } /** * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { logger.error("发生错误"); error.printStackTrace(); } public void sendMessage(String message) throws IOException { logger.debug("发送至客户端的消息:{}"+message); this.session.getBasicRemote().sendText(message); } /** * 获取所有websocket */ public CopyOnWriteArraySet<WebSocketServer> getWebSockets() { return webSocketSet; } /** * 群发自定义消息 */ public void sendInfo(String message) throws IOException { for (WebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { logger.error("sendInfo error:{}",e); } } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } }

【调用方法】

@Autowired WebSocketService service; service.sendMessage(message);

存在的问题:直接调用sendMessage()会获取不到session,所以我会调用sendInfo。

最新回复(0)