Qt 发送端一次发送多条数据,但接收端只接收一次总的数据

Qt 发送端一次发送多条数据,但接收端只接收一次总的数据


在发送端使用 TcpSocket 向接收端同时发送多条数据,但是接收端只能收到总的数据。网络上称这种情况为 ”粘包“,虽然 TcpSocket 的传输方式为数据流,但用“粘包”这一名词形容这种现象还是很贴切的。

在这里插入图片描述
在这里插入图片描述

  • 产生粘包的原因

    TCP 基于数据流传输,Write()Read() 的次数不固定,可能在读之前就合并了。

  • 粘包的解决方法(自定义包头结构)

    模拟电报的发送方式,将需要发送的数据打包成数据包,数据包分成包头和包体,包头表示需要接收数据的大小,包体为需要发送的数据。

    发送端发出数据包,接收端会从缓冲区接收数据包,先找到包头,在根据包头的大小确定包体数据。

    这里给出的代码为如何设置数据包,具体的发送与接收,可看这一篇博客 Qt—处理TCP粘包

    1 发送端
    QByteArray block;
    QDataStream out(&block,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_5_9); //设置数据流的版本,发送端和客户端版本需要一致
    out << (quint16)0; // 设置包头
    out << "22222"; //需要发送的数据
    out.device()->seek(0);
    out << (quint16)(block.size() - sizeof(quint16)); // 确定包体的大小
    tcpSocket->write(block);
    
    2 接收端
    //这里需要注意 blockSize 的初始化问题,blockSize 为 quint16 类型的全局变量
    //message 可为QString,也可为 QByteArray 
    QTcpSocket *sock = (QTcpSocket*) sender();
    QDataStream in(sock);
    in.setVersion(QDataStream::Qt_5_9);
    //刚开始接收数据
    if(blockSize == 0) {
        //判断接收的数据是否大于两个字节,也是数据大小信息所占空间
        //如果是则保存到 blockSize 中,否则继续接收数据
        if(sock->bytesAvailable() < (int)sizeof(quint16)) return ;
        in >> blockSize;
    }
    //如果没有得到全部的数据,则返回,继续接收数据
    if(sock->bytesAvailable() < blockSize) return ;
    //将接收到的数据存在变量中
    in >> message;
    

    如果发送端一次发送 n 条数据,那需要设置接收端读 n 次。

    对于接收端 socket,正确的处理粘包问题的方式是 :先将缓冲区中的数据读取出来,再拆包,而不是边读取边分包。

网上给出了处理方式都是采用自定义包头结构,但是,依旧没有解决一发一读的问题,还是多次发送,一次读取,只是能把数据分开

参考博客:

TCP粘包产生的原因、解决方法及Qt项目代码实现

Qt—处理TCP粘包


版权声明:本文为weixin_46870692原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。