处理粘包的方式是在消息头部加上消息总长度。
采用该格式:
消息总长度len(4字节)+命令字commandId(4字节)+消息msg。
思路是用一个buffer,每次有消息就读完,然后判断buffer长度,收到四字节长度len后,根据len收消息,当buffer.size()>=len,这时已经收到一个完整的包就可以处理了,处理完后就将buffer前len个字节删除掉,如此反复。
//socket有数据到来就读
connect(m_socket, SIGNAL(readyRead()), this, SLOT(ReadData()));
void Foo::ReadData()
{
m_buf->append(m_socket->readAll()); //buf是QByteArray指针,可以在类内定义
int ret = 1;
while (ret > 0)
{
ret = TryDecode(*m_buf);
if (ret < 0)
qDebug() << "TryDecode() failed";
else if (ret > 0)
m_buf->remove(0, ret);
}
}
int Foo::TryDecode(QByteArray& buf)
{
if (buf.size() < 4)
return 0;
quint32 len = qFromBigEndian(*(qint32*)buf.data());
//限制长度
if (len > 1024 * 1024 * 1024)
return -1;
if (buf.size() >= len)
{
qint32 commandId = qFromBigEndian(*(qint32*)(buf.data() + 4));
qDebug() << "recv commandId: " << commandId;
if (commandId == MsgType::heartbeat)
qDebug() << "recv heartbeat";
if (commandId == MsgType::other)
{
//处理other消息
}
return len;
}
return 0;
}