文章目录
- 1. 消息推送常见方式
- 1.1 轮询 VS 长轮询
- 1.2 SSE(server-sent event)服务器发送事件
- 2. websocket介绍
- 2.1 介绍
- 2.2 原理
- 2.3 websoket API
- 2.3.1 客户端【浏览器】API
- 2.3.2 服务端API
- 3. 代码实现
- 3.1 流程分析
- 3.2 pom依赖
- 3.3 配置类
- 3.4 消息格式
- 3.5 消息类
- 4. 前端代码(非视频源码)
参考视频
【后端&网络&大数据&数据库目录贴】
1. 消息推送常见方式
- 轮询
- 长轮询
- websocket
- SSE
1.1 轮询 VS 长轮询
1.2 SSE(server-sent event)服务器发送事件
- SSE在服务器和客户端之间打开一个单向通道
- 服务端响应的不再是一次性的数据包,而是text/event-stream类型的数据流信息
- 服务器有数据变更时将数据流式传输到客户端
2. websocket介绍
2.1 介绍
websocket是一种基于TCP链接上进行
全双工
通信的协议
- 全双工:允许数据在两个方向上
同时
传输。(TCP
是全双工,HTTP
是基于TCP的)- 半双工:允许数据在两个方向上传输,但是
同一个时间段
内只允许一个方向上传输。
2.2 原理
ws://localhost?chat
依然是http协议Connection:Upgrade
和Upgrade: websocket
表明连接升级响应码 101
说明已经切换成功
2.3 websoket API
2.3.1 客户端【浏览器】API
- websocket对象创建
let ws=new WebSocket(URL);
- websocket对象相关事件
- websocket对象提供的方法
2.3.2 服务端API
- 服务端如何接收客户端发送的数据呢?
- 服务端如何推送数据给客户端呢?
3. 代码实现
3.1 流程分析
3.2 pom依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
3.3 配置类
3.4 消息格式
3.5 消息类
@ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfigurator.class)
@Component
public class ChatEndpoint {public static final Map<String, Session> sessionsMap = new ConcurrentHashMap<>();private HttpSession httpSession;/*** 建立websocket连接后,被调用** @param session*/@OnOpenpublic void onOpen(Session session, EndpointConfig config) {//1.将session进行保存this.httpSession = (HttpSession) config.getUserProperties().get("httpSession");String userName = (String) httpSession.getAttribute("userName");ChatEndpoint.sessionsMap.put(userName, session);//2. 广播消息,需要将登录的所有的用户推送给所有用户String sendMessage = MessageUtil.sendMessage(true, null, userName + "上线");boardcast(sendMessage);}/*** 广播消息*/private void boardcast(String message) {// 遍历 map 集合Set<Map.Entry<String, Session>> entries = ChatEndpoint.sessionsMap.entrySet();for (Map.Entry<String, Session> entry : entries) {Session session = entry.getValue();try {session.getBasicRemote().sendText(message);} catch (IOException e) {// 记录日志}}}@OnMessagepublic void onMessage(String message) {try {String fromName = (String) this.httpSession.getAttribute("userName");// 将消息推送给指定的用户 message : {"toName":"张三","message":"你好"}ClientMessage clientMessage = JSON.parseObject(message, ClientMessage.class);Session session = ChatEndpoint.sessionsMap.get(clientMessage.getToName());String sendMessage = MessageUtil.sendMessage(false, fromName, clientMessage.getMessage());session.getBasicRemote().sendText(sendMessage);} catch (IOException e) {throw new RuntimeException(e);}}/*** 当websocket连接断开时,此方法会被处罚*/@OnClosepublic void onClose(Session session) {
// 从在线用户集合中剔除断开连接的用户String userName = (String) this.httpSession.getAttribute("userName");ChatEndpoint.sessionsMap.remove(userName);// 通知其他用户当前用户下线String sendMessage = MessageUtil.sendMessage(true, null, userName + "上线");boardcast(sendMessage);}
}
4. 前端代码(非视频源码)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="js/jquery.min.js"></script>
</head>
<body>
<p>【fromUserId】:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>【toUserId】:<div><input id="toUserId" name="toUserId" type="text" value="20"></div>
<p>【发送的消息】:<div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【收到的内容】:<div><textarea id="receText"></textarea></div><button id="openSocket">开启socket</button><button id="sendMessage">发送消息</button><button id="closeWs">关闭连接</button>
<script>$(function (){console.log('加兹阿勒')const urlParams = new URLSearchParams(window.location.search);console.log(urlParams)var fromUserId = urlParams.get('fromUserId');$('#userId').val(fromUserId)})var ws ;function openSocket() {if(typeof(WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");}else{console.log("您的浏览器支持WebSocket");//实现化WebSocket对象,指定要连接的服务器地址与端口 建立连接//等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");//var socketUrl="${request.contextPath}/im/"+$("#userId").val();var socketUrl="http://localhost:8081/chat";socketUrl=socketUrl.replace("https","wss").replace("http","ws");console.log(socketUrl);if(ws !=null){ws .close();ws =null;}ws = new WebSocket(socketUrl);// 当 WebSocket 成功建立连接时触发ws.onopen = function(event) {console.log("WebSocket is connected now.");// 在这里你可以发送一些初始消息到服务器// ws.send("Hello, Server!");};// 当接收到来自服务器的消息时触发ws.onmessage = function(event) {console.log("Received data from server: " + event.data);// 处理从服务器接收到的数据var parse = JSON.parse(event.data);$('#receText').val(parse.message);};// 当 WebSocket 连接关闭时触发ws.onclose = function(event) {if (event.wasClean) {console.log("WebSocket connection closed cleanly, code=" + event.code + " reason=" + event.reason);} else {// 例如,服务器进程被终止而关闭console.log("WebSocket connection died");}};// 当 WebSocket 连接出现错误时触发ws.onerror = function(error) {console.error("WebSocket Error: " + error);};}}function sendMessage() {if(typeof(WebSocket) == "undefined") {console.log("您的浏览器不支持WebSocket");}else {console.log("您的浏览器支持WebSocket");console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');ws.send('{"toName":"'+$("#toUserId").val()+'","message":"'+$("#contentText").val()+'"}');}}function closeWs(){ws.close();}$("#openSocket").on('click', openSocket);$("#sendMessage").on('click',sendMessage);$("#closeWs").on('click', closeWs);
</script>
</body>
</html>