WebSocket通信过程及原理
所属分类 websocket
浏览量 47
建立连接
WebSocket 属于应用层协议,依赖传输层的 TCP 协议,通过 HTTP/1.1 协议的 101 状态码进行握手建立连接。
具体过程
客户端发送一个 HTTP GET 请求到服务器,请求的路径是 WebSocket 的路径(类似 ws://example.com/socket)。
请求中包含一些特殊的头字段,如 Upgrade: websocket 和 Connection: Upgrade,以表明客户端希望升级连接为 WebSocket。
服务器收到这个请求后,会返回一个 HTTP 101 状态码(协议切换协议)。
同样在响应头中包含 Upgrade: websocket 和 Connection: Upgrade,
以及一些其他的 WebSocket 特定的头字段,例如 Sec-WebSocket-Accept,用于验证握手的合法性。
客户端和服务器之间的连接从普通的 HTTP 连接升级为 WebSocket 连接。之后,
客户端和服务器之间的通信就变成了 WebSocket 帧的传输,而不再是普通的 HTTP 请求和响应。
示例
// 客户端请求
GET ws://localhost:8888/ HTTP/1.1
Host: localhost:8888
Connection: Upgrade
Upgrade: websocket
Origin: http://localhost:63342
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,ja;q=0.8,en;q=0.7
Sec-WebSocket-Key: b7wpWuB9MCzOeQZg2O/yPg==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
// 服务端响应
HTTP/1.1 101 Web Socket Protocol Handshake
Connection: Upgrade
Date: Wed, 22 Nov 2023 08:15:00 GMT
Sec-WebSocket-Accept: Q4TEk+qOgJsKy7gedijA5AuUVIw=
Server: TooTallNate Java-WebSocket
Upgrade: websocket
Sec-WebSocket-Key 与服务端响应头部的 Sec-WebSocket-Accept 是配套的,提供基本的防护,比如恶意的连接,或者无意的连接;
Sec-WebSocket-Accept 根据请求头部的 Sec-WebSocket-Key 计算而来,
计算过程大致为基于 SHA1 算法得到摘要并转成 base64 字符串。
Sec-WebSocket-Extensions
用于协商本次连接要使用的 WebSocket 扩展。
数据通信
WebSocket 的每条消息可能会被切分成多个数据帧(最小单位)。
发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧并将关联的帧重新组装成完整的消息。
数据帧
帧头(Frame Header)
FIN(1比特):表示这是消息的最后一个帧。如果消息分成多个帧,FIN 位在最后一个帧上设置为 1。
RSV1、RSV2、RSV3(各1比特):保留位,用于将来的扩展。
Opcode(4比特):指定帧的类型,如文本帧、二进制帧、连接关闭等。
WebSocket 定义了几种帧类型,其中最常见的是文本帧(Opcode 为 0x1)和二进制帧(Opcode 为 0x2)。
其他帧类型包括连接关闭帧、Ping 帧、Pong 帧等。
Mask(1比特):指示是否使用掩码对负载进行掩码操作。
Payload Length:指定数据的长度。
如果小于 126 字节,直接表示数据的长度。
如果等于 126 字节,后面跟着 16 比特的无符号整数表示数据的长度。
如果等于 127 字节,后面跟着 64 比特的无符号整数表示数据的长度。
掩码(Masking)
如果 Mask 位被设置为 1,则帧头后面的 4 字节即为掩码,用于对负载数据进行简单的异或操作,以提高安全性。
负载数据(Payload Data)
实际要传输的数据,可以是文本、二进制数据等
Client: FIN=1, opcode=0x1, msg="hello"
Server: (process complete message immediately) Hi.
Client: FIN=0, opcode=0x1, msg="and a"
Server: (listening, newmessage containing text started)
Client: FIN=0, opcode=0x0, msg="happy new"
Server: (listening, payload concatenated to previous message)
Client: FIN=1, opcode=0x0, msg="year!"
Server: (process complete message) Happy new year to you too!
维持连接
当建立连接后,连接可能因为网络等原因断开,可以使用心跳的方式定时检测连接状态。
若连接断开,可以告警或者重新建立连接。
关闭连接
WebSocket 是全双工通信,当客户端发送关闭请求时,服务端不一定立即响应,而是等服务端也同意关闭时再进行异步响应。
客户端关闭的例子
Client: FIN=1, opcode=0x8, msg="1000"
Server: FIN=1, opcode=0x8, msg="1000"
上一篇
下一篇
WebSocket介绍
netty内置编解码器
MQTT与WebSocket
websocket 聊天室简单例子
netty http server 实例
netty 趣事