QT开发中文网

// 构造数据包 QByteArray packet; packet.append(char(0xCD)); // 协议头 QByteArray nameData; QDataStream nameStream(&nameData, QIODevice::WriteOnly); nameStream

在接收数据时,首先需要确定协议头和协议尾,以保证接收到的数据是完整的。根据代码中发送数据的格式,可以得知协议头为 0xCD,协议尾为 0xDC。

在 readyRead 信号的槽函数中,可以通过调用 QTcpSocket 的 readAll() 函数来获取所有可读取的数据,并将其保存到 QByteArray 类型的变量中。

接下来需要根据发送数据格式解析接收到的数据。具体做法是:先从 QByteArray 中提取出协议头、文件名长度、文件名、块数和每块大小等信息;然后按照块数循环读取每一块内容,并将其拼接起来保存到本地文件。

以下是一个可能实现方式(仅供参考):

// 定义状态机
enum State {
    WAIT_HEADER,        // 等待协议头
    READ_FILENAME_LEN,  // 读取文件名长度
    READ_FILENAME,      // 读取文件名
    READ_BLOCK_COUNT,   // 读取块数
    READ_BLOCK_SIZE,    // 读取每块大小
    READ_CONTENT_SIZE,  // 读取内容大小
    READ_CONTENT        // 读取内容
};

QByteArray receivedData;     // 存储已经接收到但未处理完整的数据包
quint16 fileNameLen = 0;    // 文件名长度
QString fileName;           // 文件名(UTF-8编码)
quint64 blockCount = 0;     // 块数
quint64 blockSize = 0;      // 每块大小
quint64 receivedBlockCount = 0;     // 已经接收到的块数
quint64 currentBlockSize = 0;       // 当前块的大小
QFile file("your_file_path", this); // 待保存文件

State state = WAIT_HEADER;

connect(socket, &QTcpSocket::readyRead, [=]() {
    QByteArray buffer = socket->readAll();
    receivedData.append(buffer);

    while (!receivedData.isEmpty()) {
        switch (state) {
            case WAIT_HEADER:
                if (receivedData[0] == char(0xCD)) {
                    receivedData.remove(0, 1);
                    state = READ_FILENAME_LEN;
                } else {
                    qDebug() << "Invalid protocol header";
                    return;
                }
                break;

            case READ_FILENAME_LEN:
                if (receivedData.length() < sizeof(quint16)) {
                    return;
                }
                QDataStream nameLenStream(receivedData);
                nameLenStream >> fileNameLen;
                receivedData.remove(0, sizeof(quint16));
                state = READ_FILENAME;
                break;

            case READ_FILENAME:
                if (receivedData.length() < fileNameLen) {
                    return;
                }
                fileName = QString::fromUtf8(receivedData.left(fileNameLen));
                receivedData.remove(0, fileNameLen);
                state = READ_BLOCK_COUNT;
                break;

            case READ_BLOCK_COUNT:
                if (receivedData.length() < sizeof(quint64)) {
                    return;
                }
                QDataStream blockCountStream(receivedData);
                blockCountStream >> blockCount;
               receivedBlockCount= 0;// 初始化已经接收到的块数为0
               file.setFileName(fileName);// 设置要保存的文件名
               if(!file.open(QIODevice::WriteOnly)){
                   qDebug()<<"Failed to open file for writing";
                   return;
               }
                receivedData.remove(0, sizeof(quint64));
                state = READ_BLOCK_SIZE;
                break;

            case READ_BLOCK_SIZE:
                if (receivedData.length() < sizeof(quint64)) {
                    return;
                }
                QDataStream blockSizeStream(receivedData);
                blockSizeStream >> blockSize;
                receivedData.remove(0, sizeof(quint64));
                state = READ_CONTENT_SIZE;
                break;

            case READ_CONTENT_SIZE:
                 if (receivedData.length() < sizeof(quint64)) {
                     return;
                 }
                 QDataStream contentBlockSizeStream(receivedData);
                 contentBlockSizeStream >> currentBlockSize;//读取当前块的大小
                 receivedBlockCount++;//已接收到的块数加1
                 receivedData.remove(0, sizeof(quint64));
                 state = READ_CONTENT;
                 break;

            case READ_CONTENT:
                  if (receivedData.length() < currentBlockSize) {
                      return;
                  }
                  QByteArray contentBlock = receivedData.left(currentBlockSize);//提取出当前块的内容
                  file.write(contentBlock);//将当前块的内容写入文件
                  receivedData.remove(0, currentBlockSize);
                  
                  // 如果所有块都已经接收完毕,就关闭文件并返回
                  if (receivedBlockCount >= blockCount) {
                      file.close();
                      qDebug() << "File saved successfully";
                      return;
                  } else {
                      state = READ_CONTENT_SIZE; // 继续读取下一块的大小
                  }
                  
                  break;

            default:
                qDebug() << "Unknown state";
        }
    }
});

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://qt.0voice.com/?id=1909

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?