当前位置: 代码网 > it编程>编程语言>Java > 详解WebSocket

详解WebSocket

2024年08月02日 Java 我要评论
相信我,进来看看,一文聊明白websocket和JAVA中的websocket。

目录

1.websocket是什么?

2.websocket的通信过程

3.websocket的报文结构

4.java中的websocket


1.websocket是什么?

在传统的bs体系中,请求响应一直是单向的,服务器一直扮演的”被动“的角色,浏览器发起请求去访问服务器,服务器才会返回响应。这种单向的模式让实时通信、消息推送一类的场景,实现起来成本巨大。

html5里面提出了websocket标准,目的就是让服务器具有”主动“的能力,能由服务器向浏览器主动推送东西。websocket 是一种基于 tcp 协议的应用层协议,它允许客户端和服务器之间建立持久连接,实现实时通信和推送功能,其和http属于并列的关系:

 

2.websocket的通信过程

websocket的通信分为两个阶段:

  • 握手阶段

  • 数据交换阶段

握手阶段:

  • 客户端通过 http 请求发起握手请求,请求头包含一些特殊的字段,如pgrade: websocket和 connection: upgrade,以及其他的 websocket 相关字段。

  • 服务器响应握手:服务器收到客户端的 websocket 握手请求后,进行协议升级,将 http 连接升级为 websocket 连接。服务器返回一个 websocket 握手响应,响应头中包含特殊字段,如 upgrade: websocketconnection: upgrade,以及其他的 websocket 相关字段。

  • 连接建立:一旦客户端收到服务器的 websocket 握手响应,websocket 连接就建立成功,现在客户端和服务器都可以发送和接收 websocket 消息了。

数据交换阶段:

  • 双向数据交换:websocket 连接建立后,客户端和服务器可以通过 websocket 会话进行双向的数据交换。任何一方都可以随时发送消息给对方,而不需要事先发出请求。这使得客户端和服务器能够实时交流和传输数据。

  • 数据帧:websocket 使用数据帧(frame)来传输数据。数据帧是 websocket 数据的最小传输单元。数据帧可以被分割成多个片段来传输更大的数据。数据帧中包含了有效载荷(payload)和一些控制信息,例如标识消息类型、是否为最后一个片段等。

  • 心跳检测:websocket 连接建立后,客户端和服务器可以通过发送心跳数据帧来维持连接。心跳检测可以确保连接的持久性,如果在一段时间内没有收到心跳响应,可以判断连接已断开。

3.websocket的报文结构

websocket的报文=结束标志位 + 操作码 + 帧长度 + 掩码

  • 第一位“fin”:相当于 http/2 里的“end_stream”,表示数据发送完毕。一个消息可以拆成多个帧,接收方看到“fin”后,就可以把前面的帧拼起来,组成完整的消息。

  • “fin”后面的三个位是保留位,目前没有任何意义,但必须是 0。

  • “opcode”,操作码:其实就是帧类型,比如 1 表示帧内容是纯文本,2 表示帧内容是二进制数据,8 是关闭连接,9 和 10 分别是连接保活的 ping 和 pong。

  • 掩码标志位“mask”:表示帧内容是否使用异或操作(xor)做简单的加密。目前的 websocket 标准规定,客户端发送数据必须使用掩码,而服务器发送则必须不使用掩码。

  • “payload len”:表示帧内容的长度。它是另一种变长编码,最少 7 位,最多是 7+64 位,也就是额外增加 8 个字节,所以一个 websocket 帧最大是 2^64。

  • “masking-key”:掩码密钥,它是由上面的标志位“mask”决定的,如果使用掩码就是 4 个字节的随机数,否则就不存在。

4.java中的websocket

websocket作为一个html5标准,也就是前端提出的标准,后端服务器需要支持这种标准,也就是能准确解析websocket的数据包,按照约定的标准来办事儿,才能使用websocket。

java 的 servlet 3.1 规范中包含了对 websocket 的支持,也就是说支持servlet 3.1的web server就支持websocket。实际开发中常用的tomcat、netty都支持websocket。

这里给出spring boot中使用websocket的demo。其底层是用的tomcat支持的websocket标准。

依赖:

websocket处理器:

每一个 websocket 连接对应一个 websocketsession。当客户端通过 websocket 建立连接时,服务器会为每个连接创建一个 websocketsession 对象,用于表示该连接的会话信息。

处理器用于处理websocketsession。

import org.springframework.stereotype.component;
import org.springframework.web.socket.textmessage;
import org.springframework.web.socket.websockethandler;
import org.springframework.web.socket.websocketmessage;
import org.springframework.web.socket.websocketsession;

@component
public class mywebsockethandler implements websockethandler {

    @override
    public void afterconnectionestablished(websocketsession session) throws exception {
        system.out.println("websocket 连接建立:" + session.getid());
    }

    @override
    public void handlemessage(websocketsession session, websocketmessage<?> message) throws exception {
        string payload = message.getpayload().tostring();
        system.out.println("接收到消息:" + payload);
        session.sendmessage(new textmessage("服务器收到消息:" + payload));
    }

    @override
    public void handletransporterror(websocketsession session, throwable exception) throws exception {
        system.err.println("websocket 传输错误:" + session.getid());
    }

    @override
    public void afterconnectionclosed(websocketsession session, closestatus closestatus) throws exception {
        system.out.println("websocket 连接关闭:" + session.getid());
    }

    @override
    public boolean supportspartialmessages() {
        return false;
    }
}

配置、注册websocket处理器:

import org.springframework.beans.factory.annotation.autowired;
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
public class websocketconfig implements websocketconfigurer {

    @autowired
    private mywebsockethandler websockethandler;

    @override
    public void registerwebsockethandlers(websockethandlerregistry registry) {
        registry.addhandler(websockethandler, "/ws").setallowedorigins("*");
    }
}

前端代码示例:

<!doctype html>
<html>
<head>
    <title>websocket test</title>
</head>
<body>
    <button onclick="sendmessage()">发送消息</button>
    <div id="messagebox"></div>

    <script>
        const ws = new websocket('ws://localhost:8080/ws');

        ws.onopen = function(event) {
            console.log('websocket 已连接');
        };

        ws.onmessage = function(event) {
            document.getelementbyid('messagebox').innerhtml += '<p>' + event.data + '</p>';
        };

        ws.onclose = function(event) {
            console.log('websocket 已关闭');
        };

        function sendmessage() {
            const message = prompt('请输入要发送的消息:');
            ws.send(message);
        }
    </script>
</body>
</html>

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com