一、模块引入
pro
QT += network
cmake
find_package(Qt6 REQUIRED COMPONENTS Network)
target_link_libraries(App PRIVATE Qt6::Network)
第一部分:TCP 通信 + 粘包问题解决
1. TCP 基础说明
- TCP 是面向字节流协议,无数据包边界;
- 发送端多次小数据,内核会合并发送 → 粘包;
- 接收端一次读取可能包含多条数据。
粘包本质:数据之间没有边界,接收方无法区分一条完整消息。
2. 通用解决方案(工业常用 2 种)
下文使用 「长度头」 方案实现完整 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"





