视频讲解2:https://www.douyin.com/collection/7545384881891575854/1
代码下载地址1:https://github.com/KeepTryingTo/QtWebSocket_client_server/tree/main
代码下载地址2:https://github.com/KeepTryingTo/QT_Learning/tree/main/QtWebSocket
相关链接:QT6.6.0基于QTcpSocket和QTcpServer实现多个客户端群聊
目录
第一步:Client → Server(ClientHello)协商加密参数,为密钥交换做准备
第二步:Server → Client(ServerHello + Certificate + ServerKeyExchange + ServerHelloDone)证书验证是信任链建立的核心
第三步:Client → Server(ClientKeyExchange + ChangeCipherSpec + Finished)
第四步:Server → Client(ChangeCipherSpec + Finished)
大家已经对TCP协议和http协议有所了解,并且前面我们还将SSL/TLS协议应用到我们的高性能webserver项目中,保证传输数据加密。但是后面我们还是会提及TCP协议和http协议,因为websocket协议是建立在TCP三次握手协议基础上来进行的,和http协议也相关,是因为数据传输过程中是从http协议升级到websocket协议。
TCP协议
基于TCP协议三次握手

基于socket的连接过程

HTTP协议连接过程
由于http协议是建立在tcp三次握手的基础上的,因此首先了解tcp三次握手之后来了解http协议更好,关于http中的ssl/tls协议的四次握手过程之前大致讲过,建议还是大家仔细把这部分好好理解和梳理一下。
TinyWebServer-v2服务器新增SSL/TLS协议和Content-Encoding字段指定压缩格式,生成私钥和自签证书以及数据压缩,保证数据在传输的过程中是加密和提高传输的效率
linux上使用tcpdump工具抓包(基于TCP协议的客户端向服务端发送信息,以及使用SSL/TLS协议之后客户端向服务端发送信息)和wireshark工具分析抓包(linux/C/C++)

我们这里只看SSL四次握手,前面的TCP三次握手跳过:
第一步:Client → Server(ClientHello)协商加密参数,为密钥交换做准备
+-----------------------------+
| ClientHello |
+-----------------------------+
| Version | TLS 1.2 |
| Random | 32字节随机数 |
| Cipher Suites | 支持的加密套件|
| Session ID | (可选) |
+-----------------------------+
第二步:Server → Client(ServerHello + Certificate + ServerKeyExchange + ServerHelloDone)证书验证是信任链建立的核心
+-----------------------------------+
| ServerHello |
+-----------------------------------+
| Version | 选定TLS版本 |
| Random | 32字节服务器随机数 |
| Cipher Suite | 选定加密套件 |
| Session ID | (如需恢复) |
+-----------------------------------+
| Certificate |
+-----------------------------------+
| 服务器证书链(包含公钥) |
+-----------------------------------+
| ServerKeyExchange (ECDHE密钥交换算法) |
+-----------------------------------+
| DH/ECDH参数(若证书不含密钥信息) |
+-----------------------------------+
| ServerHelloDone |
+-----------------------------------+
第三步:Client → Server(ClientKeyExchange + ChangeCipherSpec + Finished)
+-----------------------------------+
| ClientKeyExchange |
+-----------------------------------+
| 预主密钥(Pre-Master Secret) |
| 用服务器公钥加密后传输 |
+-----------------------------------+
| ChangeCipherSpec |
+-----------------------------------+
| 通知:后续消息启用协商的加密参数 |
+-----------------------------------+
| Finished |
+-----------------------------------+
| 加密的握手完整性验证(HMAC) |
+-----------------------------------+
第四步:Server → Client(ChangeCipherSpec + Finished)
+-----------------------------------+
| ChangeCipherSpec |
+-----------------------------------+
| 通知:后续消息启用加密 |
+-----------------------------------+
| Finished |
+-----------------------------------+
| 加密的握手完整性验证(HMAC) |
+-----------------------------------+
websocket协议
WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket通信协议于2011年被IETF定为标准RFC 6455,并由RFC7936补充规范。WebSocket API也被W3C定为标准。
websocket协议格式
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
-
FIN(1 bit):指示是否为消息的最后一个片段;
-
RSV1, RSV2, RSV3(各1 bit):保留位,用于扩展,默认为0;
-
Opcode(4 bits):定义帧的类型(如文本、二进制、控制帧等);
-
Mask(1 bit):指示负载是否被掩码(客户端到服务器的帧必须掩码);
-
Payload length(7/7+16/7+64 bits):负载长度(可能扩展);
-
Masking-key(0或4字节):如果Mask位为1,则包含32位掩码键;
-
Payload data:实际传输的数据(可能包含扩展数据和应用数据)。
websocket连接握手建立
WebSocket连接通过HTTP升级请求建立(RFC 6455 Section 4)
客户端请求消息
GET /chat HTTP/1.1 #请求行
Host: server.example.com #请求头中的服务域名(地址)
Upgrade: websocket # 告诉服务端升级为websocket
Connection: Upgrade # 连接升级
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Connection: Upgrade
- 作用:指示该连接需要“升级”到其他协议(RFC 7230 Section 6.7)。
- 与
Upgrade关系:两者必须同时存在,否则服务器会拒绝。
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
import base64, os key = base64.b64encode(os.urandom(16)) # 16字节随机数→Base64
作用:提供随机生成的Base64编码的16字节密钥(RFC 6455 Section 4.1)。
- 服务器处理:服务器需将此密钥与固定GUID拼接后计算SHA-1哈希,生成
Sec-WebSocket-Accept响应头。 - 安全性:防止意外或恶意的连接升级(如缓存污染攻击)。
Origin: http://example.com
- 作用:标识请求来源(协议+域名+端口),用于同源策略检查(RFC 6455 Section 10.2)。
- 必要性:浏览器必送,非浏览器客户端可省略。
- 安全意义:服务器可据此拒绝跨域请求。
Sec-WebSocket-Protocol: chat, superchat
- 作用:指定子协议(应用层协议),服务器需选择其中一个返回(RFC 6455 Section 4.1)。
- 示例:若服务器选择
chat,则响应头中返回Sec-WebSocket-Protocol: chat。 - 用途:区分同一WebSocket端点的不同业务逻辑。
Sec-WebSocket-Version: 13
- 作用:声明客户端支持的WebSocket协议版本(RFC 6455 Section 4.1)。
- 关键值:
13是当前标准版本,其他版本(如7、8)已废弃。
- 为什么需要掩码(Masking)(RFC 6455 Section 10.3):仅客户端→服务器的帧需要掩码,防止恶意脚本通过代理缓存攻击。
- 握手失败场景:
- 如果服务器不支持WebSocket,会返回非101状态码(如200或404)。
- 如果
Sec-WebSocket-Version不匹配,服务器返回Sec-WebSocket-Version支持的版本列表。
服务端响应消息
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
其中Sec-WebSocket-Accept
- 服务器处理:服务器需将此密钥与固定GUID拼接后计算SHA-1哈希,生成
Sec-WebSocket-Accept响应头。 - 安全性:防止意外或恶意的连接升级(如缓存污染攻击)。
import hashlib
base64 GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
accept = base64.b64encode(hashlib.sha1(key + GUID.encode()).digest())
数据帧的传输
-
数据可以分片(fragmentation)传输(RFC 6455 Section 5.4)。
- 控制帧(如Ping/Pong/Close)可以穿插在数据帧中。
- 客户端到服务器的帧必须掩码(防止代理缓存污染攻击),服务器到客户端的帧不需要掩码。
保持连接和心跳
-
WebSocket连接默认是持久化的。
- 使用Ping/Pong帧作为心跳机制(RFC 6455 Section 5.5.2/5.5.3):
- 服务器或客户端可以发送Ping帧,对方必须回复Pong帧。
- Pong帧必须包含与Ping帧相同的应用数据(如果有)。
- 心跳用于检测连接是否存活,避免超时断开。
连接释放
-
通过交换Close帧来正常关闭连接(RFC 6455 Section 5.5.1):
- 一端发送Close帧(可包含状态码和原因),另一端回复Close帧后关闭TCP连接。
- 状态码定义在RFC 6455 Section 7.4(如1000表示正常关闭)。
- 异常关闭(如TCP连接意外断开)不需要交换Close帧。
其中涉及的安全验证机制
-
Origin验证:服务器可以检查
Origin头部防止跨站请求伪造(CSRF)。 - 掩码机制:客户端到服务器的帧必须掩码,防止恶意脚本通过代理缓存攻击(RFC 6455 Section 10.3)。
- TLS加密:推荐使用
wss协议(WebSocket over TLS)保证数据机密性和完整性。 - 协议限制:WebSocket握手是有效的HTTP请求,但后续数据帧不符合HTTP格式,避免被误解。
websocket协议和http协议比较
| 特性 | HTTP | WebSocket |
|---|---|---|
| 连接方式 | 短连接(请求-响应) | 长连接(全双工) |
| 通信模式 | 半双工(客户端发起请求) | 全双工(双方可主动发送数据) |
| 头部开销 | 每个请求/响应都包含完整头部 | 初始握手后,数据帧头部很小(2-14字节) |
| 服务端推送 | 需要轮询或长轮询模拟 | 原生支持服务端主动推送 |
| 协议升级 | 无 | 通过HTTP Upgrade机制升级 |
| 数据格式 | 文本(HTTP报文) | 二进制帧(可传输文本或二进制) |
| 适用场景 | 网页浏览、API调用 | 实时通信(聊天、游戏、实时数据推送) |
QT 6.6.0中WebSocket使用
客户端页面

服务端页面

操作流程
- 第一步:分别启动服务端和客户端,加载CSS文件渲染画面和看到聊天框中加载的主机信息(右下角的灯还是暗的)
- 第二步:点击服务端“监听”按钮(服务端右下角的灯开始黄颜色)
- 第三步:客户端点击“连接服务器”按钮(客户端右下角的灯开始黄颜色)
- 第四步:等待客户端和服务端连接成功(服务端和客户端右下角的灯开始绿色)
- 第五步:客户端和服务端分别可以向对方发送消息
- 第六步:客户端和服务端可以查看连接状况;
- 第七步:可以选择断开连接
- 第八步:可以清空聊天信息
- 第九步:服务端可以点击“发送文件”按钮,客户端接收完成可以点击“下载”按钮选择保存文件位置
客户端和服务端整体通信流程
+-------------------+ +-------------------+
| Client | | Server |
+-------------------+ +-------------------+
| |
| 1. TCP连接 (WS握手) |
|------------------------------------------>|
| |
| 2. WebSocket连接建立成功 |
|<------------------------------------------|
| |
| 3. 发送文本消息 "客户端已连接!" |
|------------------------------------------>|
| |
| 4. 服务端响应文本消息 |
|<------------------------------------------|
| |
| 5. 服务端点击"发送文件"按钮 |
| 服务端准备文件并发送FILE_HEADER |
|<------------------------------------------|
| (包含文件名和大小) |
| |
| 6. 客户端发送FILE_ACK确认 |
|------------------------------------------>|
| |
| 7. 服务端开始分块发送FILE_CHUNK |
|<------------------------------------------|
| (循环发送直到文件完成) |
| |
| 8. 客户端对每个块回复FILE_CHUNK_ACK |
|------------------------------------------>|
| |
| 9. 文件传输完成 |
| |
| 10. 客户端点击"下载"保存文件 |
| |
| 11. 任意一方可发送文本消息 |
|<----------------------------------------->|
| |
| 12. 断开连接 |
|<----------------------------------------->|
| |
漂亮的图标网站
https://unicode.org/emoji/charts/full-emoji-list.html
https://emojipedia.org/emoji-mashup/twitter/twemoji-14.0?a=%F0%9F%98%80&b=%F0%9F%98%86
参考链接
https://baike.baidu.com/item/WebSocket/1953845
https://doc.qt.io/qt-6/qwebsocketserver.html
https://blog.youkuaiyun.com/gitblog_06785/article/details/147667884
https://subingwen.cn/project/websocket/#2-2-4-%E5%85%B3%E9%97%AD%E8%BF%9E%E6%8E%A5
RFC6455文档(https://www.rfc-editor.org/search/rfc_search_detail.php)
https://websocket.xiniushu.com/data-framing
QT应用案例汇总
https://mydreamambitious.blog.youkuaiyun.com/article/details/142690011?spm=1011.2415.3001.5331
5853

被折叠的 条评论
为什么被折叠?



