文章目录
- 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 消息类
参考视频
【后端&网络&大数据&数据库目录贴】
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
*/
@OnOpen
public 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) {
// 记录日志
}
}
}
@OnMessage
public 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连接断开时,此方法会被处罚
*/
@OnClose
public void onClose(Session session) {
// 从在线用户集合中剔除断开连接的用户
String userName = (String) this.httpSession.getAttribute("userName");
ChatEndpoint.sessionsMap.remove(userName);
// 通知其他用户当前用户下线
String sendMessage = MessageUtil.sendMessage(true, null, userName + "上线");
boardcast(sendMessage);
}
}