当使用 QByteArray
作为TCP数据包时,常见的问题是粘包和分包。下面给出一个示例代码,演示如何处理TCP数据包的粘包和分包情况:
class TcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit TcpServer(QObject* parent = nullptr) : QTcpServer(parent) {}
protected:
void incomingConnection(qintptr socketDescriptor) override
{
TcpSocket* socket = new TcpSocket(this);
if (socket->setSocketDescriptor(socketDescriptor)) {
connect(socket, &TcpSocket::readyRead, this, &TcpServer::processReadyRead);
connect(socket, &TcpSocket::disconnected, this, &TcpServer::removeSocket);
m_sockets.append(socket);
} else {
delete socket;
}
}
private slots:
void processReadyRead()
{
TcpSocket* socket = qobject_cast<TcpSocket*>(sender());
if (!socket)
return;
QByteArray buffer = socket->readAll();
m_receiveBuffer.append(buffer);
while (true) {
// 检查接收缓冲区中是否有足够的数据可以解析
if (m_receiveBuffer.size() < 4)
break;
quint16 header = qFromBigEndian<quint16>(reinterpret_cast<const uchar*>(m_receiveBuffer.constData()));
quint16 dataLength = qFromBigEndian<quint16>(reinterpret_cast<const uchar*>(m_receiveBuffer.constData() + 2));
// 检查接收缓冲区中是否有完整的数据包
if (m_receiveBuffer.size() < 4 + dataLength)
break;
QByteArray packetData = m_receiveBuffer.mid(4, dataLength);
m_receiveBuffer = m_receiveBuffer.mid(4 + dataLength);
// 对提取出来的packetData进行处理或解析
processPacketData(packetData);
}
}
void removeSocket()
{
TcpSocket* socket = qobject_cast<TcpSocket*>(sender());
if (!socket)
return;
m_sockets.removeOne(socket);
socket->deleteLater();
}
private:
QList<TcpSocket*> m_sockets;
QByteArray m_receiveBuffer;
void processPacketData(const QByteArray& packetData)
{
// 在这里对接收到的完整数据包进行处理或解析
qDebug() << "Received packet: " << packetData;
}
};
class TcpSocket : public QTcpSocket
{
Q_OBJECT
public:
explicit TcpSocket(QObject* parent = nullptr) : QTcpSocket(parent) {}
signals:
void readyRead();
protected:
void incomingConnection(qintptr socketDescriptor) override
{
emit readyRead();
}
};
在上述代码中,我们使用了一个自定义的 TcpServer
类继承自 QTcpServer
,并监听传入的连接。每当有新连接进来时,会创建一个 TcpSocket
对象,并将其添加到管理列表中。
在 TcpServer
中的槽函数 processReadyRead()
中,我们首先读取到可用数据后将其追加到接收缓冲区 m_receiveBuffer
中。然后,通过循环不断尝试解析数据包:检查缓冲区是否有足够长度(至少4个字节)以及是否有完整的数据包,如果满足条件,则提取出数据并将其从接收缓冲区中移除。最后,我们对提取出来的数据包调用 processPacketData()
进行处理。
需要注意的是,在示例代码中,我们使用了自定义的 TcpSocket
类继承自 QTcpSocket
,并重写了 incomingConnection()
方法。这样可以通过发射 readyRead()
信号触发 processReadyRead()
槽函数,以便及时处理接收到的数据。
以上就是一个简单的TCP粘包和分包处理的示例代码,具体实现仍然需要根据你的需求进行适当修改和调整。
内容由零声教学AI助手提供,问题来源于学员提问