WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需完成一次握手,两者之间就可以直接创建持久性的连接,并进行双向数据传输。
WebSocket定义
WebSocket是独立的,创建在TCP上的协议。
WebSocket通过HTTP/1.1协议的101状态码进行握手
为了创建WebSocket连接,需要通过浏览器发出请求,之后服务器进行回应,这个过程称为"握手"
基于浏览器定时发送请求,然后由服务器返回最新的数据给客户端浏览器,这种传统模式,需要浏览器不断发送请求,HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,这样会浪费很多的带宽资源。在这种情况下,HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时的通讯。
WebSocket优缺点
不支持无连接: WebSocket 是一种持久化的协议,这意味着连接不会在一次请求之后立即断开。这是有利的,因为它消除了建立连接的开销,但是也可能导致一些资源泄漏的问题。 不支持广泛: WebSocket 是 HTML5 中的一种标准协议,虽然现代浏览器都支持,但是一些旧的浏览器可能不支持 WebSocket。 需要特殊的服务器支持: WebSocket 需要服务端支持,只有特定的服务器才能够实现 WebSocket 协议。这可能会增加系统的复杂性和部署的难度。 数据流不兼容: WebSocket 的数据流格式与 HTTP 不同,这意味着在不同的网络环境下,WebSocket 的表现可能会有所不同。
WebSocket通信流程
1.浏览器发起http请求,,请求建立webSocket连接
2.服务器响应同意协议更改
3.相互发送数据
Java实现WebSocket的方式
基于注解实现
-
引入SpringBoot中webSocket的启动器
-
编写配置类,注入ServerEndpointExporter组件
-
创建服务端消息监听类 并使用@ServerEndPoint标识类,标识这是一个webSocket的服务点
-
@OnOpen连接成功
-
@OnClose连接关闭
-
@OnMessage收到消息状态
@ServerEndpoint("/wsServer") @Slf4j @Component public class WsServer { private static Map<String,Session> sessionMap=new HashMap<>(); //客户端连接服务端时触发 @OnOpen public void onOpen(Session session){ log.debug("客户端连接服务端..."); sessionMap.put(session.getId(),session); } //客户端向服务端发送消息时触发 public String onMessage(String text){ log.debug("接收到客户端消息+"+text); return text; } //客户端发送关闭连接时触发 @OnClose public void onClose(Session session){ log.debug("客户端关闭连接"); sessionMap.remove(session.getId()); } //服务端主动发送消息 @Scheduled(fixedRate = 2000) public void sendMsg() throws IOException { //向所有连接的客户端发送消息 Set<Map.Entry<String, Session>> entries = sessionMap.entrySet(); for (Map.Entry<String, Session> entry : entries) { entry.getValue().getBasicRemote().sendText("hello webSocket"); } } }
基于spring提供的接口和类实现
-
和注解方式一样,需要引入webSocket的启动器
-
编写webSocket服务断点类,继承Spring提供的AbstractWebSocketHandler抽象类,重写其中的方法。
@Component @Slf4j public class WebSocketListener extends AbstractWebSocketHandler { private Map<String, WebSocketSession> sessionMap=new HashMap<>(); //连接建立后触发 @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { super.afterConnectionEstablished(session); log.debug(session.getId()+":连接建立成功"); sessionMap.put(session.getId(), session); } //接收消息后触发 @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super.handleTextMessage(session, message); log.debug("收到"+session.getId()+"发送的消息,消息内容:"+message.getPayload()); } //连接关闭后触发 @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { super.afterConnectionClosed(session, status); log.debug("关闭连接..."); if(session.isOpen()){ sessionMap.remove(session.getId()); } } //服务端主动发送消息 @Scheduled(fixedRate = 2000) public void sendMsg() throws IOException { //向所有连接的客户端发送消息 log.debug("客户端发送消息"); Set<Map.Entry<String, WebSocketSession>> entries = sessionMap.entrySet(); for (Map.Entry<String, WebSocketSession> entry : entries) { entry.getValue().sendMessage(new TextMessage("hello websocket")); } } }
-
自定义拦截器类继承自spring提供的HttpSessionHandshakeInteceptor抽象类,添加握手前后的操作
@Component @Slf4j public class MyInteceptorHandler extends HttpSessionHandshakeInterceptor { //握手前 @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { log.debug("握手前..."); return super.beforeHandshake(request, response, wsHandler, attributes); } //握手后 @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { log.debug("握手后"); super.afterHandshake(request, response, wsHandler, ex); } }
-
编写配置类实现自WebSocketConfigure接口,注册上面自定义实现类。
@Configuration @EnableWebSocket public class MyWebSocketConfigure implements WebSocketConfigurer { @Autowired private WebSocketListener webSocketListener; @Autowired private MyInteceptorHandler inteceptorHandler; @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(webSocketListener,"/webSocket2") .addInterceptors(inteceptorHandler) .setAllowedOrigins("*"); } }
WebSocket常见应用场景
1.弹幕:每个客户端发送消息到服务器,由服务器统一整理后发回客户端
2.消息实时提醒:后端主动推送新的变动至客户端
3.聊天功能
4.在线游戏
所有和客户端需要实时获取服务端数据时的场景。