问题一:当传输数据过大时,readAll不能读完这一条完整的报文
报文格式如下:
![](https://img-blog.csdnimg.cn/20191016192434839.png)
解决方法:针对此问题,可以通过一个全局变量,将多次读到的数据合并
![](https://img-blog.csdnimg.cn/20191016195304753.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3h1bWluZ3lpZnJlbmQ=,size_16,color_FFFFFF,t_70)
问题二:粘包现象之多次write对应一次read
深入查看ReadyRead()信号的产生条件可知:
1、发送端Write一次,那么接收方就会有新数据到达,ReadyRead()信号就会触发一次,这种说法是错误的。
2、发送方和接收方没有一 一对应关系,发送端Write()函数调用一次,假如这一次Write了较大数据(2M),那么接收方ReadyRead()信号往往会触发两次以上,反过来,如果发送方Write()函数被调用了两次或是以上,接收方的ReadyRead()信号也可能只调用一次。经过程序证明这是正确的。
3、文档中说有新的数据来,ReadyRead()信号就会触发一次,其实,这里说新的数据来,不是说从发送端有新的数据来到你的机子,而是数据从你的Tcp/ip协议栈到达你的Qt应用程序,也就是系统io缓冲区到达Qt应用程序,数据从系统到达你的Qt应用程序一次,readyread信号就会触发一次。还有一个非常要注意的词就是“only once”,仅仅一次。什么意思呢?其实是这样的,第一次数据来的时候,触发一次readyread信号,但如果此时你的readyread槽函数还没有及时执行,而新的数据又来了而且来了很多次(在QTcpSocket缓存没有满的情况下,满的情况下系统不会再发数据给应用),那么,这些所有的都将会只再触发一次readyread信号。如果此时你的readyread槽函数执行了,那么这时候来的新的数据就会触发第三个readyread信号。也就是说,还没有响应的readyread信号最多只有两个。想想也是啊,如果我发送端一直发送数据,你的系统就一直将数据发送给你的应用,然后readyread信号一直触发,触发到成千上万个,那岂不是很傻的操作。
想了解更多请参考如下两篇文章:
https://blog.csdn.net/u012372584/article/details/82751527
https://blog.csdn.net/lusa1314/article/details/83306774
解决方法:针对此问题,可以通过报尾的特殊标签或者解析报头中的报文长度进行分包处理
问题三:粘包现象之N次write对应M次read
现象:read读到的数据包括多条完整的报文和一条不完整的报文(最后一条不完整)
解决方法:针对此问题,可以通过自定义全局变量receivedData保存每一次readAll的数据,然后对readAll进行分包处理,对最后一条完整的报文应与下N次读到的报文结合后再处理。具体代码如下:
void socket::processReadyRead()
{
//0、message用于保存一条有效报文
QString message = "";
//1、读取此次readready()信号的数据
receivedData += QString(static_cast<QTcpSocket*>(sender())->readAll().data());
while(1)
{
//2、判断报文长度
if(packetLength == 0) //判断前15个字符
{
if(receivedData.size() < 15) //表示第N条报文的报头未接收完
{
return;
}
else //判断第N条报文的有效内容长度
{
QString text = receivedData.mid(6 , 13);
for(int i = 0 ; i < 8 ; i++)
{
if(text.mid(0 , 1) == "0")
{
text = text.mid(1 , 8-1-i);
}
else
{
break;
}
}
packetLength = text.toInt();
qDebug() << "packetLength : " << packetLength;
}
}
//3、读取有效内容
if(receivedData.size() >= (15 + packetLength)) //第N条报文读取完毕
{
message = receivedData.mid(0 , (15+packetLength)); //第N条有效报文
receivedData = receivedData.mid(15 + packetLength); //剩下的未读报文
differentInstructionParsing(message); //解析第N条报文
}
packetLength = 0;
}
}
欢迎大家指教,希望大家喜欢
路漫漫其修远兮,同志仍须努力