【qt】通过TCP传输json,json里包含图像

主要是使用协议头

发送方

cpp 复制代码
        connect(m_pDetectWorker, &DetectionWorker::sig_detectImg, this, [=](const QJsonObject &json){
            // 转换为JSON数据
            QJsonDocument doc(json);
            QByteArray jsonData = doc.toJson(QJsonDocument::Compact);

            // 构建增强协议头
            struct EnhancedHeader {
                quint32 magic = 0x4A534F4E; // "JSON"
                quint32 version = 1;        // 协议版本
                quint32 dataSize;
                quint32 checksum;
                quint8 dataType;           // 0=JSON, 1=Image, 2=Text等
                char timestamp[20];        // 时间戳
                char reserved[15];
            };

            EnhancedHeader header;
            header.dataSize = jsonData.size();
            header.dataType = 0; // JSON数据类型

            // 计算校验和
            quint32 checksum = 0;
            for (int i = 0; i < jsonData.size(); ++i) {
                checksum += static_cast<quint8>(jsonData[i]);
            }
            header.checksum = checksum;

            // 添加时间戳
            QByteArray timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toUtf8();
            memcpy(header.timestamp, timestamp.constData(), qMin(timestamp.size(), 19));
            header.timestamp[19] = '\0';

            memset(header.reserved, 0, sizeof(header.reserved));

            // 发送给所有客户端
            foreach(QTcpSocket* client, clients) {
                if(client->state() == QAbstractSocket::ConnectedState) {
                    client->setSocketOption(QAbstractSocket::LowDelayOption, 1);

                    // 发送协议头
                    client->write(reinterpret_cast<const char*>(&header), sizeof(header));
                    // 发送JSON数据
                    client->write(jsonData);
                }
            }
        });

接收方

cpp 复制代码
void OnlineFrameViewModel::receiveImageData()
{
    QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());
    if(!socket) return;

    // 定义协议头结构(与发送端一致)
    struct EnhancedHeader {
        quint32 magic;          // 魔数 "JSON"
        quint32 version;        // 协议版本
        quint32 dataSize;       // 数据大小
        quint32 checksum;       // 校验和
        quint8 dataType;        // 数据类型
        char timestamp[20];     // 时间戳
        char reserved[15];      // 保留字段
    };

    static QByteArray receivedDataBuffer;
    receivedDataBuffer.append(socket->readAll());

    // 处理可能存在的多个数据包(粘包处理)
    while (!receivedDataBuffer.isEmpty()) {
        // 如果缓冲区大小不足以包含协议头,等待更多数据
        if (receivedDataBuffer.size() < sizeof(EnhancedHeader)) {
            return;
        }

        // 提取协议头
        EnhancedHeader header;
        memcpy(&header, receivedDataBuffer.constData(), sizeof(EnhancedHeader));

        // 验证魔数
        if (header.magic != 0x4A534F4E) { // "JSON"
            qDebug() << u8"无效的数据包魔数,清空缓冲区";
            receivedDataBuffer.clear();
            return;
        }

        // 检查是否收到完整的数据包(协议头 + 数据)
        if (receivedDataBuffer.size() < sizeof(EnhancedHeader) + header.dataSize) {
            // 数据不完整,等待更多数据
            return;
        }

        // 提取JSON数据
        QByteArray jsonData = receivedDataBuffer.mid(sizeof(EnhancedHeader), header.dataSize);

        // 验证校验和
        quint32 calculatedChecksum = 0;
        for (int i = 0; i < jsonData.size(); ++i) {
            calculatedChecksum += static_cast<quint8>(jsonData[i]);
        }

        if (calculatedChecksum != header.checksum) {
            qDebug() << u8"数据校验失败,丢弃数据包";
            // 移除损坏的数据包
            receivedDataBuffer.remove(0, sizeof(EnhancedHeader) + header.dataSize);
            continue;
        }

        // 移除已处理的数据包
        receivedDataBuffer.remove(0, sizeof(EnhancedHeader) + header.dataSize);

        // 解析JSON数据
        QJsonParseError jsonError;
        QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &jsonError);

        if(jsonError.error != QJsonParseError::NoError) {
            qDebug() << u8"JSON解析错误:" << jsonError.errorString();
            continue;
        }

        if(jsonDoc.isObject()) {
            QJsonObject jsonObj = jsonDoc.object();

            // 处理图像数据(原有逻辑保持不变)
            if(jsonObj.contains("image_path")) {
                QString jsonOriPath = jsonObj["image_path"].toString();//原始路径,pc1的路径
                QString imgPath;


                // 指定检测 E 盘
                QStorageInfo volume("Y:/");

                if (volume.isValid()) {
                    // 双工控机测试是肯定存在
                    imgPath = jsonOriPath.replace(u8"E:/raw图/","Y:/");

                    emit sig_sendMsg(u8"检测路径:"+ imgPath);
                    QFileInfo fileInfo(imgPath);
                    if (!fileInfo.exists()) {
                        qCritical() << "Error: Path does not exist:" << imgPath;
                        continue; // 继续处理下一个数据包
                    }
                } else {
                    emit sig_sendMsg("Y:/ is not a valid volume.");
                    imgPath = jsonOriPath;

                    emit sig_sendMsg(u8"Y盘读取失败,检查PLC网口的网络情况");

                    emit sig_sendMsg(u8"检测路径:"+ imgPath);
                    QFileInfo fileInfo(imgPath);
                    if (!fileInfo.exists()) {
                        qCritical() << "Error: Path does not exist:" << imgPath;
                        continue; // 继续处理下一个数据包
                    }
                }
                QImage enhanceImg(imgPath);

                //=============================👇=============================
                if(jsonObj.contains("image_data")) {
                    QString base64String = jsonObj["image_data"].toString();
                    QByteArray byteArray = QByteArray::fromBase64(base64String.toUtf8());
                    QImage img;
                    if (img.loadFromData(byteArray)) {
                        qDebug() << u8"图片加载成功,尺寸为:" << img.size();
                        enhanceImg = img;
                    } else {
                        qDebug() << u8"图片加载失败";
                    }
                }

                //=============================👆=============================

                QSharedPointer<ImageDataInfo> imgInfo(new ImageDataInfo);

                imgInfo->imageFilePath = imgPath;
                imgInfo->enhanceImg = enhanceImg;
                imgInfo->barcode = jsonObj["barcode"].toString();
                imgInfo->device = jsonObj["device"].toInt();
                imgInfo->pointIndex = jsonObj["pointIndex"].toInt();
                imgInfo->skipframe = jsonObj["skipframe"].toInt();
                imgInfo->overlayframe = jsonObj["overlayframe"].toInt();
                imgInfo->kv = jsonObj["kv"].toInt();
                imgInfo->ua = jsonObj["ua"].toInt();
                imgInfo->grayMean = jsonObj["grayMean"].toInt();

                emit sig_sendMsg(u8"检测开始"+imgInfo->barcode);

                int device = imgInfo->pointIndex;
                int pointIndex = imgInfo->pointIndex;

                QtConcurrent::run([=]() {
                    saveBarcodeLog(imgInfo->barcode,device,pointIndex);
                });
                if(m_pDetectWorker!=nullptr)
                    m_pDetectWorker->enqueueImage(*imgInfo);

                emit sig_didDisplayLiveImg(enhanceImg,imgInfo->device);
            }
        }
    }
}
相关推荐
箓维1 小时前
TCP Socket的进阶实现
网络·笔记·tcp/ip
星恒随风2 小时前
Linux网络编程:应用层协议究竟是什么?从网络计算器到TCP Socket抽象基类完整实现
linux·网络·笔记·tcp/ip
飞浪纪元[FWC–FE]3 小时前
从零到一键绿:Qt 5.14.2 + VS2019 开发环境搭建、Kit 套件配置与构建错误修复完全手册
开发语言·qt
程序员大阳4 小时前
副队长JavaScript教程(65)-详解JSON:轻量级数据交换格式
javascript·json·序列化·反序列化·stringify·parse
ShineWinsu4 小时前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
Escalating_xu6 小时前
【Linux 网络编程】ARP 的具体过程与 ARP 欺骗:一条 IP → MAC 映射,怎样改变数据的去向?
linux·网络·tcp/ip
Escalating_xu7 小时前
【Linux 网络编程】IP 分片与重组:3000 字节的数据报,怎样拆开又拼回来?
linux·网络·tcp/ip
OpenLoong 开源社区7 小时前
打破 NAT 限制,零侵入跨网络通信:基于 WebRTC 的透明 TCP 隧道跨网络通信方案
网络协议·tcp/ip·开源·webrtc·openloong开源社区
ShineWinsu8 小时前
对于Qt:QPushButton常见属性的解析
开发语言·c++·qt·api·gui·按钮·qpushbutton
飞浪纪元[FWC–FE]8 小时前
Qt 工程创建与 CMake / qmake 构建规范
开发语言·数据库·qt