使用场景==========================================
先说明客户端-服务器已经可以通过http进行通信了,为什么还要使用通过websocket,http协议局限:http协议是基于请求-响应的,也就是说只有客户端发起了请求,服务端才能回应,服务端无法主动给客户端发送消息。
那这样可不行,服务端想要主动给客户端发送消息怎么办,比如说:后台系统出现问题怎么通知客户端,客户端-服务器想要建立聊天会话怎么实现,订单状态的变更如何让客户端知晓等
Server to Client的常见实现方式========================
- 长轮询(Long Polling):简单易实现,兼容性好,但效率低,延迟高。适用于不频繁需要实时数据更新的应用。
- 实现原理:客户端通过不断轮询请求服务端接口达到长连接的效果
- 服务器发送事件(Server-Sent Events, SSE):简单易用,支持自动重连,适用于实时数据更新和持续数据推送的应用,但仅支持单向通信。
- 实现原理:通过特定请求头告诉服务器,客户端希望以事件流的形式接收数据,服务端会保持连接开放状态。
- WebSocket:支持双向通信,低延迟,高效传输,适用于高频实时交互和需要实时通知更新的应用。
- 实现原理:通过一次握手建立持久连接
Websocket的实现--springboot=========================
1.引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2.配置websocket
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfiguration {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3.创建工具类方便后续使用
import javax.websocket.Session;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class WebSocketUtils {
private static final Map<String, Session> sessions = new ConcurrentHashMap<>();
public static void addSession(String sessionId, Session session) {
sessions.put(sessionId, session);
}
public static void removeSession(String sessionId) {
sessions.remove(sessionId);
}
//给某个客户端发送消息
public static void sendMessageToSession(String sessionId, String message) {
Session session = sessions.get(sessionId);
if (session != null && session.isOpen()) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
//群发
public static void sendMessageToAll(String message) {
sessions.values().forEach(session -> {
if (session.isOpen()) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
4.端点类中注册会话--就是在这里处理和客户端的消息
WebSocket 服务器可以同时与多个客户端建立连接并进行独立管理。
每个连接都有一个独立的会话session,通过 sessionId
进行标识
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
//websocket端点url
@ServerEndpoint("/ws")
public class WebSocketServer {
//初始建立连接的处理
@OnOpen
public void onOpen(Session session) {
System.out.println("Connected: " + session.getId());
WebSocketUtils.addSession(session.getId(), session);
WebSocketUtils.sendMessageToSession(session.getId(), "Welcome to the WebSocket server!");
}
//接收到客户端消息的处理
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("Received: " + message);
WebSocketUtils.sendMessageToSession(session.getId(), "Server received: " + message);
}
//连接关闭的处理
@OnClose
public void onClose(Session session) {
System.out.println("Disconnected: " + session.getId());
WebSocketUtils.removeSession(session.getId());
}
//连接错误的处理
@OnError
public void onError(Session session, Throwable throwable) {
System.err.println("Error for session " + session.getId() + ": " + throwable.getMessage());
WebSocketUtils.removeSession(session.getId());
}
}
5.如果要给客户端发送消息:
import org.springframework.stereotype.Service;
@Service
public class NotificationService {
public void notifyClient(String sessionId, String message) {
//发送给某一个连接
WebSocketUtils.sendMessageToSession(sessionId, message);
}
public void notifyAllClients(String message) {
//发送给所有的连接
WebSocketUtils.sendMessageToAll(message);
}
}
前端vue中与服务端建立连接并发送或接收消息示例代码:
methods: {
connectWebSocket() {
// 创建 WebSocket 连接,这里写的是服务端websocket端点url
this.socket = new WebSocket('ws://localhost:8080/ws');
// WebSocket 连接成功时触发
this.socket.onopen = () => {
console.log('WebSocket connection established');
};
// 接收到服务器消息时触发
this.socket.onmessage = (event) => {
this.serverMessage = event.data;
};
// WebSocket 连接关闭时触发
this.socket.onclose = () => {
console.log('WebSocket connection closed');
};
// WebSocket 连接发生错误时触发
this.socket.onerror = (error) => {
console.error('WebSocket error:', error);
};
},
sendMessage() {
// 向服务器发送消息
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(this.message);
}
},
}