news 2026/6/12 5:08:52

Qt 网络进阶|TCP 通信 + 粘包彻底解决 + WebSocket 实时通信

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Qt 网络进阶|TCP 通信 + 粘包彻底解决 + WebSocket 实时通信

一、模块引入

pro

QT += network

cmake

find_package(Qt6 REQUIRED COMPONENTS Network) target_link_libraries(App PRIVATE Qt6::Network)

第一部分:TCP 通信 + 粘包问题解决

1. TCP 基础说明

  • TCP 是面向字节流协议,无数据包边界;
  • 发送端多次小数据,内核会合并发送 →粘包
  • 接收端一次读取可能包含多条数据。

粘包本质:数据之间没有边界,接收方无法区分一条完整消息。

2. 通用解决方案(工业常用 2 种)

  1. 包头 + 包体:固定 4 字节表示数据长度,先读长度,再读对应字节数(推荐)
  2. 特殊分隔符:末尾加\r\n###等标记(文本协议适用)

下文使用「长度头」方案实现完整 TCP 客户端 / 服务端,并彻底解决粘包。


3. TCP 服务端(QTcpServer + QTcpSocket)

cpp

运行

#include <QApplication> #include <QMainWindow> #include <QTcpServer> #include <QTcpSocket> #include <QVBoxLayout> #include <QTextEdit> #include <QByteArray> class TcpServer : public QMainWindow { Q_OBJECT public: TcpServer() { resize(500,300); m_server = new QTcpServer(this); m_recvEdit = new QTextEdit; setCentralWidget(m_recvEdit); // 监听本机 8888 端口 if(m_server->listen(QHostAddress::Any, 8888)) m_recvEdit->append("服务端启动成功,端口:8888"); else m_recvEdit->append("服务端启动失败"); connect(m_server, &QTcpServer::newConnection, this, &TcpServer::onNewConn); } private slots: void onNewConn() { m_socket = m_server->nextPendingConnection(); m_recvEdit->append("客户端已连接"); connect(m_socket, &QTcpSocket::readyRead, this, &TcpServer::onReadData); connect(m_socket, &QTcpSocket::disconnected, m_socket, &QTcpSocket::deleteLater); } // 核心:拆包、解决粘包 void onReadData() { m_buffer += m_socket->readAll(); // 至少4字节(长度头) + 一条数据 while(m_buffer.size() >= 4) { // 读取前4字节 = 数据长度 quint32 len = *(quint32*)m_buffer.data(); if(m_buffer.size() < 4 + len) break; // 数据不完整,等待下一次接收 // 截取完整数据包 QByteArray data = m_buffer.mid(4, len); m_recvEdit->append("收到: " + QString(data)); // 移除已处理数据 m_buffer = m_buffer.mid(4 + len); } } private: QTcpServer *m_server; QTcpSocket *m_socket = nullptr; QTextEdit *m_recvEdit; QByteArray m_buffer; // 接收缓冲区 }; int main(int argc, char *argv[]) { QApplication a(argc, argv); TcpServer w; w.show(); return a.exec(); } #include "main.moc"

4. TCP 客户端(组包:添加长度头)

cpp

运行

#include <QApplication> #include <QMainWindow> #include <QTcpSocket> #include <QPushButton> #include <QLineEdit> #include <QVBoxLayout> #include <QByteArray> class TcpClient : public QMainWindow { Q_OBJECT public: TcpClient() { resize(400,200); m_socket = new QTcpSocket(this); m_edit = new QLineEdit; QPushButton *btnSend = new QPushButton("发送"); QVBoxLayout *lay = new QVBoxLayout; lay->addWidget(m_edit); lay->addWidget(btnSend); QWidget *cen = new QWidget; cen->setLayout(lay); setCentralWidget(cen); // 连接服务端 m_socket->connectToHost("127.0.0.1", 8888); connect(btnSend, &QPushButton::clicked, this, &TcpClient::sendMsg); } private slots: void sendMsg() { QString text = m_edit->text(); QByteArray data = text.toUtf8(); // 组包:前4字节长度 + 原始数据 quint32 len = data.size(); QByteArray pkg; pkg.append((char*)&len, 4); pkg.append(data); m_socket->write(pkg); m_edit->clear(); } private: QTcpSocket *m_socket; QLineEdit *m_edit; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); TcpClient w; w.show(); return a.exec(); } #include "main.moc"

5. 粘包方案总结

  • 长度头方案:二进制通信、协议交互首选,稳定性最强;
  • 分隔符方案:HTTP、串口、文本指令场景使用;
  • 必须设置接收缓冲区,循环拆包,保证每条消息完整解析。

第二部分:WebSocket 实时双向通信

WebSocket 基于 HTTP 握手,实现长连接、全双工实时通信,适合聊天室、物联网推送、网页 + Qt 交互。

1. 模块与类

  • 模块:network
  • 服务端:QWebSocketServer
  • 客户端:QWebSocket

2. WebSocket 服务端

cpp

运行

#include <QApplication> #include <QMainWindow> #include <QWebSocketServer> #include <QWebSocket> #include <QTextEdit> #include <QVBoxLayout> class WsServer : public QMainWindow { Q_OBJECT public: WsServer() { resize(500,300); m_wsServer = new QWebSocketServer("WsServer", QWebSocketServer::NonSecureMode, this); m_edit = new QTextEdit; setCentralWidget(m_edit); if(m_wsServer->listen(QHostAddress::Any, 9999)) m_edit->append("WebSocket 服务端启动,端口9999"); connect(m_wsServer, &QWebSocketServer::newConnection, this, &WsServer::onNewConn); } private slots: void onNewConn() { QWebSocket *socket = m_wsServer->nextPendingConnection(); m_edit->append("客户端接入"); connect(socket, &QWebSocket::textMessageReceived, this, [=](const QString &msg){ m_edit->append("收到消息: " + msg); // 回显 socket->sendTextMessage("服务端已收到:" + msg); }); connect(socket, &QWebSocket::disconnected, socket, &QWebSocket::deleteLater); } private: QWebSocketServer *m_wsServer; QTextEdit *m_edit; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); WsServer w; w.show(); return a.exec(); } #include "main.moc"

3. WebSocket 客户端

cpp

运行

#include <QApplication> #include <QMainWindow> #include <QWebSocket> #include <QLineEdit> #include <QPushButton> #include <QTextEdit> #include <QVBoxLayout> class WsClient : public QMainWindow { Q_OBJECT public: WsClient() { resize(400,300); m_ws = new QWebSocket; m_recvEdit = new QTextEdit; m_sendEdit = new QLineEdit; QPushButton *btnSend = new QPushButton("发送"); QVBoxLayout *lay = new QVBoxLayout; lay->addWidget(m_recvEdit); lay->addWidget(m_sendEdit); lay->addWidget(btnSend); QWidget *cen = new QWidget; cen->setLayout(lay); setCentralWidget(cen); // 连接服务端 m_ws->open(QUrl("ws://127.0.0.1:9999")); connect(m_ws, &QWebSocket::textMessageReceived, this, [=](const QString &msg){ m_recvEdit->append("服务端: " + msg); }); connect(btnSend, &QPushButton::clicked, this, &WsClient::sendMsg); } private slots: void sendMsg() { QString text = m_sendEdit->text(); m_ws->sendTextMessage(text); m_sendEdit->clear(); } private: QWebSocket *m_ws; QTextEdit *m_recvEdit; QLineEdit *m_sendEdit; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); WsClient w; w.show(); return a.exec(); } #include "main.moc"

小结

  1. TCP:面向字节流,重点解决粘包,长度头是工业标准方案,适合二进制私有协议;
  2. WebSocket:长连接实时通信,兼容网页端,适合推送、聊天、物联网;
  3. 两类接口均为异步信号驱动,禁止使用阻塞式 waitForXXX,避免 UI 卡顿。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/12 5:06:53

WinForms轻量级复选下拉框控件,支持多选项勾选与状态管理

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;这个资源包提供一个开箱即用的WinForms多选下拉框实现&#xff0c;基于原生ComboBox扩展而来&#xff0c;无需第三方UI库。核心是CheckedComboBox控件类&#xff0c;内部封装了复选框绘制、鼠标点击响应、键盘导…

作者头像 李华
网站建设 2026/6/12 5:04:52

第五章 Planning — 让 Agent 学会“思考“

第5章&#xff1a;Planning — 让 Agent 学会"思考" &#x1f4cc; 本章目标 理解 ReAct 模式的完整实现掌握 Chain-of-Thought&#xff08;思维链&#xff09;提示技巧学会任务分解&#xff1a;把大任务拆成小步骤实现带自我反思的 Agent 5.1 为什么 Tool Calling…

作者头像 李华
网站建设 2026/6/12 5:03:51

Pandoc终极指南:一站式解决文档格式转换难题

Pandoc终极指南&#xff1a;一站式解决文档格式转换难题 【免费下载链接】pandoc Universal markup converter 项目地址: https://gitcode.com/gh_mirrors/pa/pandoc 还在为不同文档格式之间的转换而烦恼吗&#xff1f;无论是Markdown转Word、HTML转PDF&#xff0c;还是…

作者头像 李华
网站建设 2026/6/12 5:00:52

2026这6款宝藏降AI率平台大起底,一键让AIGC率断崖式下跌!

步入 2026 年&#xff0c;学术圈的风向早已悄然改变。曾经只需盯着查重率的焦虑&#xff0c;如今已被更严苛的 AIGC 检测标准彻底取代。AI 生成内容的识别技术愈发精准&#xff0c;高校对论文原创性的要求也水涨船高。单靠降低重复率已无法满足审核需求&#xff0c;真正让无数学…

作者头像 李华
网站建设 2026/6/12 4:56:57

Hackintool终极指南:5步解决黑苹果配置难题的完整教程

Hackintool终极指南&#xff1a;5步解决黑苹果配置难题的完整教程 【免费下载链接】Hackintool The Swiss army knife of vanilla Hackintoshing 项目地址: https://gitcode.com/gh_mirrors/ha/Hackintool Hackintool是黑苹果社区中最强大的配置工具&#xff0c;被誉为&…

作者头像 李华