WebSocket 实时通信

一、WebSocket介绍

WebSocket 是一种在单个 TCP 连接上进行全双工通讯的协议,它使得客户端和服务器之间的数据交换变得更加简单、高效。WebSocket 协议在 2011 年由 IETF 标准化,并成为 HTML5 标准的一部分。WebSocket 使得客户端和服务器之间的数据交换变得更加简单、高效,允许服务端主动向客户端推送数据。

二、WebSocket使用场景

WebSocket 主要用于实时通信,如聊天、游戏、股票行情、实时监控等。WebSocket 协议的优势在于:

  1. 建立在 TCP 协议之上,相比 HTTP 协议,建立 WebSocket 连接的握手阶段更加简单,握手后数据传输更加高效。
  2. 通信双方可以主动推送数据,服务器向客户端推送数据,客户端也可以主动向服务器发送数据。
  3. 协议标识符是 ws(WebSocket)或 wss(WebSocket Secure),端口号默认是 80(ws)和 443(wss)。

三、WebSocket实现原理

WebSocket 协议在建立连接时,需要先在 HTTP 协议上完成一次握手,握手成功后,WebSocket 协议开始工作。

WebSocket 协议的通信过程如下:

  1. 客户端向服务器发起 WebSocket 连接请求,请求中包含了 HTTP 协议的请求行、请求头和请求体。
  2. 服务器收到 WebSocket 连接请求后,向客户端发送 HTTP 响应,响应中包含了 HTTP 协议的响应行、响应头和响应体。
  3. 客户端和服务器完成 WebSocket 握手,并开始 WebSocket 数据传输。
  4. WebSocket 数据传输过程中,服务器和客户端可以互相发送数据帧。
  5. WebSocket 连接一旦关闭,连接双方的 WebSocket 协议实现也会相应的关闭。

四、WebSocket框架

WebSocket 协议的实现框架有很多,如 Node.js 的 ws 模块、Java 的 javax.websocket 包、Python 的 aiohttp-websocket 库等。

五、Java WebSocket 使用

5.1 引入 WebSocket 依赖

WebSocket在spring boot项目中, 主要依赖spring-boot-starter-websocket包,该包包含了 WebSocket 相关的接口和注解。

  1. 在 pom.xml 文件中添加依赖:
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.java-websocket</groupId>
            <artifactId>Java-WebSocket</artifactId>
            <version>1.5.2</version> <!-- 确保使用合适的版本 -->
        </dependency>
        <dependency>
            <groupId>org.glassfish.tyrus.bundles</groupId>
            <artifactId>tyrus-standalone-client</artifactId>
            <version>1.20</version>
        </dependency>

2.创建WebSocketConfig.class文件,配置WebSocket相关的bean:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(new MyWebSocketHandler(), "/ws").setAllowedOrigins("*");
    }
}   

3.创建MyWebSocketHandler.class文件,实现WebSocketHandler接口:

@Component
public class MyWebSocketHandler extends TextWebSocketHandler {

    private static final Logger logger = LoggerFactory.getLogger(MyWebSocketHandler.class);

    private static final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();// 会话列表

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        sessions.add(session); // 新连接加入会话列表
        System.out.println("新客户端连接: " + session.getId());
    }

    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("收到客户端消息: " + payload);
        // 处理客户端消息
        session.sendMessage(new TextMessage("服务器收到: " + payload));
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        sessions.remove(session); // 连接关闭时移除会话
        System.out.println("客户端断开连接: " + session.getId());
    }
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        logger.error("WebSocket error on session {}: {}", session.getId(), exception.getMessage());
    }

    // 向所有客户端推送消息
    public void sendToAll(String message) {
        System.out.println("当前连接用户数: "+sessions.size());
        for (WebSocketSession session : sessions) {
            try {
                session.sendMessage(new TextMessage(message));
                System.out.println("服务端推送消息成功: " + message);
            } catch (IOException e) {
                System.err.println("推送消息失败: " + e.getMessage());
            }
        }
    }

    // 向指定客户端推送消息
    public void sendTo(WebSocketSession session, String message) {
        try {
            session.sendMessage(new TextMessage(message));
            System.out.println("服务端推送消息成功: " + message);
        } catch (IOException e) {
            System.err.println("推送消息失败: " + e.getMessage());
        }
    }

    // 获取会话列表的副本
    public List<WebSocketSession> getSessions() {
        return new ArrayList<>(sessions); // 返回副本,避免外部修改
    }

    

}

3.前端页面中,通过WebSocket连接到服务器,并接收服务器推送的消息:

var ws = new WebSocket("ws://localhost:8080/你的项目名/ws");
    // 连接成功触发
     socket.addEventListener('open', function (event) {
         socket.send('Hello Server!');
     });
    // 监听消息
    socket.addEventListener('message', function (event) {
        // console.log('Message from server ', event.data);
         // 解析后端消息
        var jsonStr = event.data;
        //*********
        
    });
    // 监听连接关闭事件
    socket.addEventListener('close', function (event) {
        console.log('连接已关闭,尝试重新连接...');
        reconnect();
    });
    // 监听错误事件
    socket.addEventListener('error', function (error) {
        console.error('WebSocket 发生错误: ', error);
    });
    
    // 重连方法
    // 若连接断开,则3秒后尝试重新连接
    function reconnect() {
        setTimeout(function () {
            console.log('重试连接...');
            socket = new WebSocket('ws://localhost:8080/bdhhk/ws');

            // 在新的连接上重新绑定事件
            socket.addEventListener('open', function (event) {
                console.log('重新连接成功,发送消息到服务器');
                socket.send('Hello Server!');
            });

            socket.addEventListener('message', function (event) {
                console.log('来自服务器的消息: ', event.data);
            });

            socket.addEventListener('close', function (event) {
                console.log('连接已关闭,尝试重新连接...');
                reconnect();
            });

            socket.addEventListener('error', function (error) {
                console.error('WebSocket 发生错误: ', error);
            });
        }, 3000); // 3秒后重试连接
    }

4.前端页面中,向服务器发送消息:

ws.send("客户端发送的消息");

六、WebSocket 安全性

WebSocket 协议本身是一种基于 TCP 协议的协议,因此,WebSocket 协议本身是安全的。但是,由于 WebSocket 协议本身的限制,WebSocket 协议并不能完全抵御中间人攻击。

七、WebSocket 常见问题

7.1 客户端与服务端建立 WebSocket 连接时,如何验证身份?

WebSocket 协议本身并没有提供身份验证机制,因此,需要服务端根据业务需求,在建立 WebSocket 连接时,服务端可以向客户端发送身份验证信息,
客户端接收到身份验证信息后,根据身份验证信息进行验证,如cookie、token等。验证通过后,才建立 WebSocket 连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值