<>QT处理TCP粘包问题

处理粘包的方式是在消息头部加上消息总长度。

采用该格式:
消息总长度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; }
<>常见数据传输场景

<>一、概念

<>1)组包。

简单的说就是tcp协议把过大的数据包分成了几个小的包传输,接收方要把同一组的数据包重新组合成一个完整的数据包。

<>2)半包。

指接受方没有接受到一个完整的包,只接受了部分,这种情况主要是由于TCP为提高传输效率,将一个包分配的足够大,导致接受方并不能一次接受完。

<>3)粘包与分包。

粘包:指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾。

出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能由接收方造成。发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。

分包:指在出现粘包的时候我们的接收方要进行分包处理。

<>二、发送端解决办法

(1) 可以每次发送同样大小的包,过大的包不予发送,过小的包,后面部分用固定的字符’\0’进行填充。

(2)将流按字符处理,抽出一个字符做转义字符(通常Java用’\’来做转义字符,比如”\n”表示换行)。

(3)在发送方发送一个包的时候,先将这个包的长度发送给对方(一般是4个字节表示包长),然后再将包的内容发送过去.接收方先接收4个字节,看看包的长度,然后按照长度来接收包。

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信