WebSocket实现前后端双向数据的实时推送

2024-06-01 1266阅读

一、WebSocket简介

        WebSocket是一种网络通信协议,旨在实现客户端和服务器之间的双向、全双工通信。它在HTML5规范中被引入,用于替代基于传统HTTP协议的长轮询、轮询和流传输等方式,以提供更高效的实时数据传输。

WebSocket实现前后端双向数据的实时推送
(图片来源网络,侵删)

WebSocket的特点

  1. 双向通信:与传统的HTTP协议不同,WebSocket允许客户端和服务器之间的双向通信。客户端和服务器都可以在任何时候发送数据,而无需等待对方先发起请求。

  2. 持久连接:WebSocket连接一旦建立,将会保持打开状态,直到客户端或服务器主动关闭连接。这减少了因频繁建立和关闭连接带来的开销。

  3. 低延迟:由于WebSocket减少了请求头信息和频繁的握手过程,通信延迟显著降低,非常适合实时应用。

  4. 基于消息:WebSocket通信是基于消息的,而不是基于请求-响应。这样可以更加灵活地传输数据。

WebSocket的工作原理

  1. 握手阶段:客户端通过HTTP请求向服务器发起WebSocket握手请求。这个请求包含一个特殊的Upgrade头部,指示服务器将连接从HTTP升级到WebSocket协议。

  2. 建立连接:服务器收到握手请求后,如果同意升级连接,则会返回一个101状态码的响应,表示协议切换成功。此时,WebSocket连接正式建立。

  3. 数据传输:连接建立后,客户端和服务器可以通过WebSocket协议相互发送消息。这些消息可以是文本或二进制数据。

  4. 关闭连接:当任意一方不再需要连接时,可以发送关闭请求来关闭WebSocket连接。连接关闭后,通信停止,资源释放。

二、数据实时推送的实现方式和应用场景

轮询 (Polling)

优点
  1. 实现简单:实现和理解起来相对容易,使用传统的HTTP请求。
  2. 浏览器兼容性好:几乎所有浏览器都支持,适用于所有的客户端。
缺点
  1. 资源浪费:频繁的HTTP请求会消耗大量带宽和服务器资源,即使没有新数据时也会发送请求。
  2. 延迟高:实时性差,因为需要等待下一个请求周期才能获取新数据。
使用场景
  • 适用于低频更新和对实时性要求不高的应用,如定时刷新页面内容。

    长连接 (HTTP Persistent Connection)

    优点
    1. 减少开销:在同一个TCP连接上进行多个HTTP请求,减少了建立和关闭连接的开销。
    2. 提高效率:适用于连续请求的场景,提高了传输效率。
    缺点
    1. 资源占用:服务器需要维护连接状态,占用资源。
    2. 不适合实时通信:虽然减少了建立连接的开销,但仍然是基于请求-响应模式,实时性不如WebSocket。
    使用场景
    • 适用于需要频繁请求数据的应用,如加载大量静态资源的网页。

      WebSocket

      优点
      1. 双向通信:客户端和服务器都可以主动发送消息,实现全双工通信。
      2. 低延迟:一旦连接建立,数据可以实时传输,延迟极低。
      3. 高效:减少了HTTP头部和握手的开销,适合高频率的数据传输。
      缺点
      1. 复杂度高:实现和维护起来比轮询复杂,需要处理连接管理、心跳检测等。
      2. 浏览器兼容性:虽然现代浏览器都支持,但在非常旧的浏览器上可能不支持。
      使用场景
      • 适用于高频率和低延迟的实时应用,如在线游戏、实时聊天、股票行情、协作编辑。

        三、代码实现

        1.pom.xml添加WebSocke依赖

        
           org.springframework.boot
           spring-boot-starter-websocket
        

         2.WebSocke配置类

        package com.example.websocketdemo;
        import org.springframework.context.annotation.Configuration;
        import org.springframework.web.socket.config.annotation.EnableWebSocket;
        import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
        import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
        @Configuration
        @EnableWebSocket // 启用WebSocket支持
        public class WebSocketConfig implements WebSocketConfigurer {
            @Override
            public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
                // 注册WebSocket处理程序,并设置WebSocket路径为 "/websocket"
                registry.addHandler(new MyWebSocketHandler(), "/websocket").setAllowedOrigins("*");
            }
        }
        

         3.WebSocke服务类

        package com.example.websocketdemo;
        import org.springframework.web.socket.CloseStatus;
        import org.springframework.web.socket.TextMessage;
        import org.springframework.web.socket.WebSocketSession;
        import org.springframework.web.socket.handler.TextWebSocketHandler;
        import java.util.Collections;
        import java.util.HashSet;
        import java.util.Set;
        public class MyWebSocketHandler extends TextWebSocketHandler {
            // 用于存储所有活动的WebSocket会话
            private static final Set sessions = Collections.synchronizedSet(new HashSet());
            // 处理接收到的文本消息
            @Override
            protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
                String payload = message.getPayload(); // 获取消息内容
                System.out.println("Received: " + payload); // 打印接收到的消息
                session.sendMessage(new TextMessage("Server received: " + payload)); // 回复消息给客户端
                // 发送当前连接人数
                broadcast("Current number of connections: " + sessions.size());
            }
            // 处理WebSocket连接建立
            @Override
            public void afterConnectionEstablished(WebSocketSession session) throws Exception {
                sessions.add(session); // 添加会话到集合
                System.out.println("Connected: " + session.getId());
                // 发送当前连接人数
                broadcast("New connection established. Current number of connections: " + sessions.size());
            }
            // 处理WebSocket连接关闭
            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
                sessions.remove(session); // 从集合中移除会话
                System.out.println("Disconnected: " + session.getId());
                // 发送当前连接人数
                broadcast("Connection closed. Current number of connections: " + sessions.size());
            }
            // 向所有连接的客户端广播消息
            private void broadcast(String message) {
                for (WebSocketSession session : sessions) {
                    if (session.isOpen()) {
                        try {
                            session.sendMessage(new TextMessage(message));
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
        

          3.创建启动类

        package com.example.websocketdemo;
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        @SpringBootApplication
        public class WebsocketDemoApplication {
            public static void main(String[] args) {
                SpringApplication.run(WebsocketDemoApplication.class, args); // 启动Spring Boot应用
            }
        }
        

        四、测试WebSocket连接

        可以使用浏览器的控制台进行测试:

        let socket = new WebSocket("ws://localhost:8080/websocket");
        socket.onopen = function(e) {
          console.log("[open] Connection established");
          socket.send("Hello Server!"); // 发送消息给服务器
        };
        socket.onmessage = function(event) {
          console.log(`[message] Data received from server: ${event.data}`); // 处理服务器返回的消息
        };
        socket.onclose = function(event) {
          if (event.wasClean) {
            console.log(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
          } else {
            console.error('[close] Connection died'); // 处理连接关闭
          }
        };
        socket.onerror = function(error) {
          console.error(`[error] ${error.message}`); // 处理错误
        };
        
VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]