详解WebSocket

简介: 详解WebSocket

1.WebSocket是什么?

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


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

b72faab2f6064766ab94f990872c240a.png


2.WebSocket的通信过程

04225ed95eac462db60783a815375e60.png


WebSocket的通信分为两个阶段:


握手阶段


数据交换阶段


握手阶段:


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


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


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


数据交换阶段:


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


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


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


3.WebSocket的报文结构

20200228092445882.png


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标准。


依赖:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>


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>
目录
相关文章
|
网络协议 数据安全/隐私保护 Windows
了解WebSocket
熟悉下websocket协议的相关原理和优缺点
354 0
了解WebSocket
|
Web App开发 移动开发 JavaScript
WebSocket的了解(一)
WebSocket的了解(一)
326 0
WebSocket的了解(一)
|
前端开发 C++ 开发者
用mongols轻松打造websocket应用
用websocket做聊天系统是非常合适的。 mongols是一个运行于linux系统之上的开源c++库,可轻松开启一个websocket服务器。 首先,build一个websocket服务器。 #include //websocket server int main(int,char**){ int port=9090; const char* host="127.0.0.1"; mongols::ws_server server(host,port); server.run(); }   才几行,这就成了吗?没错!不信你用wsdump.py测试下。
1226 0
|
移动开发 网络协议 Java
WebSocket就是这么简单
前言 今天在慕课网上看到了Java的新教程(Netty入门之WebSocket初体验):https://www.imooc.com/learn/941 WebSocket我是听得很多,没有真正使用过的技术。
1610 0
|
缓存 前端开发 网络协议
WebSocket的理解与使用
WebSocket是一种基于HTTP的长链接技术。传统的HTTP协议是一种请求-响应模型,如果浏览器不发送请求,那么服务器无法主动给浏览器推送数据。如果需要定期给浏览器推送数据,例如股票行情,或者不定期给浏览器推送数据,例如在线聊天,基于HTTP协议实现这类需求,只能依靠浏览器的JavaScript定时轮询,效率很低且实时性不高。
|
5月前
|
移动开发 网络协议 前端开发
H5与WebSocket
H5与WebSocket
|
移动开发 缓存 网络协议
WebSocket就是这么简单(一)
今天在慕课网上看到了Java的新教程(Netty入门之WebSocket初体验):https://www.imooc.com/learn/941 WebSocket我是听得很多,没有真正使用过的技术。我之前也去了解过了WebSocket究竟是什么东西,不过一直没有去实践过。 我在写监听器博文的时候,在线人数功能用监听器的是来做,在评论有说使用WebSocket的方式会更加好。 那么,我们就来探究一下WebSocket究竟是什么东西,顺便了解一下Netty。!
181 0
|
Web App开发 网络协议 应用服务中间件
|
8月前
|
存储 网络协议 JavaScript
WebSocket相关知识
WebSocket相关知识
|
监控 数据可视化 应用服务中间件
为什么要用webSocket?
为什么要用webSocket?
126 0

热门文章

最新文章