解决QT中TCP传数据的困惑

问题一:当传输数据过大时,readAll不能读完这一条完整的报文

报文格式如下:

解决方法:针对此问题,可以通过一个全局变量,将多次读到的数据合并

 

问题二:粘包现象之多次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;
    }
}

 

欢迎大家指教,希望大家喜欢

路漫漫其修远兮,同志仍须努力

 

  • 5
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xumingyifrend

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值