Qt WebSocket 协议编程实战
1. WebSocket 协议概述
WebSocket 是一种基于单个 TCP 连接提供全双工(Full-Duplex)通信信道的网络技术。与传统的 HTTP 请求/响应模型不同,WebSocket 在连接建立后,客户端与服务器可以双向、实时、低延迟地收发数据,无需反复握手。
- 标准化:IETF 将其标准化为RFC 6455
- 握手:通过 HTTP 的
Upgrade头完成协议升级(HTTP/1.1 101 Switching Protocols),握手完成后数据在同一个 TCP 连接上以**帧(frame)**的形式传输 - 协议标识:
ws://(明文)与wss://(基于 TLS 加密,默认端口 443) - 默认端口:
ws为 80,wss为 443 - 典型用途:实时聊天、股票/行情推送、在线游戏、服务端主动推送通知等
在 Qt 中,QWebSocket既可用于客户端应用程序,也可用于服务器端(配合QWebSocketServer)构建 WebSocket 服务。
2. QWebSocket Class(客户端)
QWebSocket继承自QObject,用于在客户端发起并管理一个 WebSocket 连接。
2.1 头文件与链接
#include<QWebSocket>- 需要在
.pro文件中添加:QT += websockets - CMake 中:
find_package(Qt6 COMPONENTS WebSockets REQUIRED)并链接Qt6::WebSockets
2.2 连接与断开
QWebSocket socket;// 发起连接(异步)socket.open(QUrl("ws://localhost:1234"));// 连接成功信号connect(&socket,&QWebSocket::connected,this,[](){qDebug()<<"Connected";});// 可选:设置是否忽略 SSL 错误(仅用于测试环境,生产谨慎)connect(&socket,&QWebSocket::sslErrors,&socket,QOverload<constQList<QSslError>&>::of(&QWebSocket::ignoreSslErrors));// 主动关闭socket.close();2.3 收发数据
// 发送文本消息socket.sendTextMessage(QStringLiteral("Hello, Server!"));// 发送二进制消息QByteArray data=QByteArray::fromHex("48656c6c6f");socket.sendBinaryMessage(data);// 接收文本消息connect(&socket,&QWebSocket::textMessageReceived,this,[](constQString&msg){qDebug()<<"Text received:"<<msg;});// 接收二进制消息connect(&socket,&QWebSocket::binaryMessageReceived,this,[](constQByteArray&data){qDebug()<<"Binary received, size:"<<data.size();});3. QWebSocketServer Class(服务器)
QWebSocketServer用于在服务器端监听并接受 WebSocket 客户端连接,创建一个 WebSocket 服务。
3.1 启动服务器
#include<QWebSocketServer>QWebSocketServerserver(QStringLiteral("My Server"),QWebSocketServer::NonSecureMode);// 明文模式// 或使用 SecureMode(需要配置 SSL 证书)// QWebSocketServer server(QStringLiteral("My Server"),// QWebSocketServer::SecureMode);if(server.listen(QHostAddress::Any,1234)){qDebug()<<"Listening on port"<<server.serverPort();}3.2 处理新连接与消息
// 新客户端接入connect(&server,&QWebSocketServer::newConnection,this,[&server](){QWebSocket*client=server.nextPendingConnection();qDebug()<<"New client:"<<client->peerAddress().toString();connect(client,&QWebSocket::textMessageReceived,this,[client](constQString&msg){client->sendTextMessage("Echo: "+msg);// 回显});connect(client,&QWebSocket::disconnected,client,&QObject::deleteLater);});4. 相关 API 一览
4.1 QWebSocket 主要方法
| 方法 | 说明 |
|---|---|
open(const QUrl &url) | 发起连接到指定 WebSocket 地址 |
close(CloseCode code = NormalClosure) | 关闭连接 |
sendTextMessage(const QString &message) | 发送文本消息 |
sendBinaryMessage(const QByteArray &data) | 发送二进制消息 |
abort() | 立即中止连接 |
requestUrl() | 返回请求的 URL |
state() | 返回当前连接状态(QAbstractSocket::SocketState) |
error()/errorString() | 获取错误信息 |
4.2 QWebSocket 主要信号
| 信号 | 说明 |
|---|---|
connected() | 连接建立成功 |
disconnected() | 连接断开 |
textMessageReceived(const QString &) | 收到文本消息 |
binaryMessageReceived(const QByteArray &) | 收到二进制消息 |
stateChanged(QAbstractSocket::SocketState) | 连接状态变化 |
errorOccurred(QAbstractSocket::SocketError) | 发生错误 |
sslErrors(const QList<QSslError> &) | SSL 错误 |
4.3 QWebSocketServer 主要方法
| 方法 | 说明 |
|---|---|
listen(const QHostAddress &, quint16 port) | 开始监听 |
nextPendingConnection() | 取出下一个待处理的客户端连接 |
close() | 停止监听 |
hasPendingConnections() | 是否有待处理的连接 |
serverPort() | 返回实际监听的端口 |
4.4 QWebSocketServer 主要信号
| 信号 | 说明 |
|---|---|
newConnection() | 有新客户端连接 |
closed() | 服务器关闭 |
acceptError(QAbstractSocket::SocketError) | 接受连接出错 |
4.5 重要枚举
QWebSocketProtocol::Version:协议版本(VersionLatest/Version13等)QWebSocketServer::SslMode:NonSecureMode/SecureModeQWebSocketProtocol::CloseCode:关闭码(NormalClosure、GoingAway等)
5. 完整实战示例
下面是一个同时包含客户端与服务器的完整示例,便于快速验证。
5.1 服务器端(main.cpp)
#include<QCoreApplication>#include<QWebSocketServer>#include<QWebSocket>#include<QDebug>intmain(intargc,char*argv[]){QCoreApplicationa(argc,argv);QWebSocketServerserver(QStringLiteral("Echo Server"),QWebSocketServer::NonSecureMode);QObject::connect(&server,&QWebSocketServer::newConnection,[&server](){QWebSocket*client=server.nextPendingConnection();qDebug()<<"Client connected:"<<client->peerAddress().toString();QObject::connect(client,&QWebSocket::textMessageReceived,[client](constQString&msg){qDebug()<<"Received:"<<msg;client->sendTextMessage(QStringLiteral("Echo: ")+msg);});QObject::connect(client,&QWebSocket::disconnected,client,&QObject::deleteLater);});if(server.listen(QHostAddress::Any,1234)){qDebug()<<"Server listening on port"<<server.serverPort();}else{qDebug()<<"Listen failed";return1;}returna.exec();}5.2 客户端端(main.cpp)
#include<QCoreApplication>#include<QWebSocket>#include<QDebug>intmain(intargc,char*argv[]){QCoreApplicationa(argc,argv);QWebSocket socket;QObject::connect(&socket,&QWebSocket::connected,[&socket](){qDebug()<<"Connected, sending message...";socket.sendTextMessage(QStringLiteral("Hello, Server!"));});QObject::connect(&socket,&QWebSocket::textMessageReceived,[](constQString&msg){qDebug()<<"Server said:"<<msg;});QObject::connect(&socket,&QWebSocket::disconnected,&a,&QCoreApplication::quit);// 连接过程中发生错误QObject::connect(&socket,&QWebSocket::errorOccurred,[](QAbstractSocket::SocketError e){qDebug()<<"Error:"<<e;});socket.open(QUrl(QStringLiteral("ws://localhost:1234")));returna.exec();}5.3 .pro 文件
QT += core websockets CONFIG += c++17 SOURCES += main.cppQt WebSocket 聊天系统 — 服务端 + 客户端案例
| 项目 | 角色 | 说明 |
|---|---|---|
QWebsocketServerPrs | 服务端 | 消息中转站,监听 8899 端口,管理连接、群发/私发/转发消息 |
untitled40 | 客户端 | 聊天界面,连接服务器、发送/接收消息 |
两个项目配套使用才能组成一个完整的多人聊天系统。
1. 两个项目是什么关系
┌─────────────────────┐ ws://192.168.x.x:8899 ┌─────────────────────┐ │ QWebsocketServerPrs │ ◄──────────────────────────────► │ untitled40 │ │ (服务端) │ │ (客户端) │ │ 监听 8899 端口 │ 可有多个客户端同时连接 │ 填写地址+名称连接 │ └─────────────────────┘ └─────────────────────┘QWebsocketServerPrs(服务端) | untitled40(客户端) | |
|---|---|---|
| 核心类 | QWebSocketServer | QWebSocket |
| 数量 | 1 个 | 可以开很多个(多个人聊天) |
| 职责 | 监听端口、管理连接、群发/私发/转发 | 发起连接、发送消息、接收并显示消息 |
客户端把"自己的名字"当 origin 传给服务器,服务器靠
socket->origin()认人、靠 JSON 里的dst转发消息。
整体代码仓库地址
HTTPS:https://github.com/wuyongGitHub/qt-websocket-chat.git
SSH:git@github.com:wuyongGitHub/qt-websocket-chat.git
多客户端连接服务端效果
群发消息效果
私发消息效果
客户端相互发消息效果
整体效果:
6. 常见问题与注意事项
根据前端开发业务流,总结一下websocket使用事项
- 心跳保活:长时间空闲的连接可能被中间设备断开,建议定期发送 ping(Qt 会自动响应 ping/pong,可手动
ping()检测存活)。 - 线程模型:
QWebSocket非线程安全,跨线程使用时需通过信号槽或QMetaObject::invokeMethod调度到所属线程。 - 错误处理:务必连接
errorOccurred信号,网络异常时才能及时感知并重连。 - 大文件传输:二进制消息适合传输大块数据,但需注意分帧与内存占用,必要时自行设计分片协议。
- 安全:生产环境应使用
wss://(SecureMode)并正确配置证书,避免明文传输敏感数据。 - 释放时机:客户端断开连接后,服务器端应及时
deleteLater释放QWebSocket对象,防止内存泄漏。