You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QTcpServer接收QTcpSocket的QString崩溃,求助排查QDom解析问题

QTcpServer解析XML数据问题排查与修复

我搭建了一个QTcpServer程序,用于接收QTcpSocket发送的XML字符串。已确认两者能正常建立连接,且能在服务器端显示XML字符串,但解析后无法正确处理数据,怀疑问题出在QDom解析或updateRow函数中。

服务器端代码

mainwindow.h

#include <QMainWindow>
#include <QTableView>
#include <QPushButton>
#include <QTextEdit>
#include <QStandardItemModel>
#include <QTcpServer>
#include <QTcpSocket>

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void startServer();
    void handleConnection();
    void readMessage();
    void ReadXML(QString XMLString);
    void Add_to_CV(QString C, QString Con, int Pn, int Bh, int Bb, int Bl, int Bw);
    void Add_to_CV(QString C, QString Con, int Pn, int Ch, int Cd, int Cw);
public slots:
    void updateRow(QStandardItem *item);
private:
    QPushButton *SServer;
    QTableView *ContainerView;
    int Pallet_Number;
    QStandardItemModel *HMod;
    QTcpServer *tcpServer;
    QTcpSocket *tcpSocket;
};

mainwindow.cpp

#include "mainwindow.h"
#include <QLabel>
#include <QLayout>
#include <QDebug>
#include <QDomDocument>
#include <QRegularExpression>

static QRegularExpression Box_Code("B");
static QRegularExpression Cylinder_Code("C");

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent),
      SServer(new QPushButton("Start Listening")),
      ContainerView(new QTableView),
      tcpServer(new QTcpServer),
      tcpSocket(new QTcpSocket)
{
    QStringList HeaderRow;
    HeaderRow.append("Pallet");
    HeaderRow.append("Container");
    HeaderRow.append("Code");
    HeaderRow.append("Height");
    HeaderRow.append("Breadth/Diameter");
    HeaderRow.append("Length");
    HeaderRow.append("Weight");
    HMod = new QStandardItemModel;
    HMod->setHorizontalHeaderLabels(HeaderRow);
    // 新增:关联表格视图与数据模型
    ContainerView->setModel(HMod);
    resize(800,300);
    connect(SServer, &QPushButton::clicked, this, &MainWindow::startServer);
    connect(tcpServer, &QTcpServer::newConnection, this, &MainWindow::handleConnection);
    connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::handleConnection);
    connect(HMod, SIGNAL(itemchanged(QStandardItem*)), this, SLOT(updateRow(QStandardItem*)));
    QLabel *Lab1(new QLabel("Listening on Port 6164"));
    QHBoxLayout *HB(new QHBoxLayout);
    QVBoxLayout *VB(new QVBoxLayout);
    HB->addWidget(SServer);
    HB->addWidget(Lab1);
    VB->addItem(HB);
    VB->addWidget(ContainerView);
    QWidget *window(new QWidget);
    window->setLayout(VB);
    setCentralWidget(window);
}

MainWindow::~MainWindow()
{
}

void MainWindow::startServer()
{
    if(!tcpServer->listen(QHostAddress::LocalHost, 6164)){
        qDebug() << "Error connecting to Server";

        tcpServer->close();
        return;
    } else {
        qDebug() << "Started Successfully";
    }
}

void MainWindow::handleConnection()
{
    tcpSocket = tcpServer->nextPendingConnection();
    qDebug() << "New Connection!";
    connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::readMessage);
}

void MainWindow::readMessage()
{
    ContainerView->clearSpans(); //clear table to prepare for new XMLString
    QByteArray buffer = tcpSocket->readAll();
    QString FromContainer = QString::fromUtf8(buffer);
    ReadXML(FromContainer);
}

void MainWindow::ReadXML(QString XMLString)
{
    QDomDocument xRead;
    // 新增:检查XML解析是否成功
    if(!xRead.setContent(XMLString)){
        qDebug() << "XML parse failed";
        return;
    }
    QDomElement root = xRead.documentElement();
    if(root.tagName() == "Pallets")
    {
        QDomElement Pallet = root.firstChildElement();
        int PNum;
        bool ok;
        // 修正:Pallet循环逻辑,将nextSiblingElement移到循环内部
        while(!Pallet.isNull())
        {
            PNum = Pallet.attribute("Number").toInt(&ok);
            QDomElement Box_Cyl = Pallet.firstChildElement();
            while(!Box_Cyl.isNull())
            {
                int CHei, CLen, CBre, CWei;
                QString Container, CCode;
                Container = Box_Cyl.tagName();
                if(Box_Cyl.tagName() == "Box")
                {
                    QDomElement Code = Box_Cyl.firstChildElement();
                    CCode = Code.text();
                    QDomElement Height = Code.nextSiblingElement();
                    CHei = Height.text().toInt(&ok);
                    // 修正:用当前节点的nextSiblingElement遍历,保证顺序正确
                    QDomElement Length = Height.nextSiblingElement();
                    CLen = Length.text().toInt(&ok);
                    QDomElement Breadth = Length.nextSiblingElement();
                    CBre = Breadth.text().toInt(&ok);
                    QDomElement Weight = Breadth.nextSiblingElement();
                    CWei = Weight.text().toInt(&ok);
                    Add_to_CV(CCode, Container, PNum, CHei, CBre, CLen, CWei);
                }else if(Box_Cyl.tagName() == "Cylinder")
                {
                    QDomElement Code = Box_Cyl.firstChildElement();
                    CCode = Code.text();
                    QDomElement Height = Code.nextSiblingElement();
                    CHei = Height.text().toInt(&ok);
                    QDomElement Diameter = Height.nextSiblingElement();
                    CBre = Diameter.text().toInt(&ok);
                    QDomElement Weight = Diameter.nextSiblingElement();
                    CWei = Weight.text().toInt(&ok);
                    Add_to_CV(CCode, Container, PNum, CHei, CBre, CWei);
                }
                Box_Cyl = Box_Cyl.nextSiblingElement();
            }
            Pallet = Pallet.nextSiblingElement();
        }
    }
}

void MainWindow::Add_to_CV(QString C, QString Con, int Pn, int Bh, int Bb, int Bl, int Bw)
{
    QList<QStandardItem*> row;
    // 修正:数值转字符串初始化Item,避免角色值误用
    QStandardItem *Pallet_Num_Item = new QStandardItem(QString::number(Pn));
    QStandardItem *Container_Type = new QStandardItem(Con);
    QStandardItem *Box_Code = new QStandardItem(C);
    QStandardItem *Box_Height = new QStandardItem(QString::number(Bh));
    QStandardItem *Box_Breadth = new QStandardItem(QString::number(Bb));
    QStandardItem *Box_Length = new QStandardItem(QString::number(Bl));
    QStandardItem *Box_Weight = new QStandardItem(QString::number(Bw));
    row << Pallet_Num_Item << Container_Type << Box_Code << Box_Height << Box_Breadth << Box_Length << Box_Weight;
    HMod->appendRow(row);
}

void MainWindow::Add_to_CV(QString C, QString Con, int Pn, int Ch, int Cd, int Cw)
{
    QList<QStandardItem*> row;
    // 修正:数值转字符串初始化Item
    QStandardItem *Pallet_Num_Item = new QStandardItem(QString::number(Pn));
    QStandardItem *Container_Type = new QStandardItem(Con);
    QStandardItem *Cylinder_Code = new QStandardItem(C);
    QStandardItem *Cylinder_Height = new QStandardItem(QString::number(Ch));
    QStandardItem *Cylinder_Diameter = new QStandardItem(QString::number(Cd));
    QStandardItem *Cylinder_Blank = new QStandardItem(); //Cylinder does not have a Length
    QStandardItem *Cylinder_Weight = new QStandardItem(QString::number(Cw));
    row <<Pallet_Num_Item << Container_Type << Cylinder_Code << Cylinder_Height << Cylinder_Diameter << Cylinder_Blank << Cylinder_Weight;
    HMod->appendRow(row);
}

void MainWindow::updateRow(QStandardItem *item)
{
    QColor colour = Qt::white;
    int row = item->row();
    // 修正:避免空指针访问
    QStandardItem *codeItem = HMod->item(row, 2);
    if (codeItem && codeItem->data(Qt::DisplayRole).toFloat() >= 200)
        colour = Qt::red;
    // 修正:遍历全列,且检查Item是否存在
    for (int col=0; col<7; col++){
        QStandardItem *cellItem = HMod->item(row, col);
        if(cellItem)
            cellItem->setBackground(colour);
    }
}

发送的XML内容

<Pallets>
  <Pallet Number="1">
    <Box>
      <Code>B123</Code>
      <Height>200</Height>
      <Length>300</Length>
      <Breadth>150</Breadth>
      <Weight>50</Weight>
    </Box>
    <Cylinder>
      <Code>C456</Code>
      <Height>400</Height>
      <Diameter>200</Diameter>
      <Weight>80</Weight>
    </Cylinder>
  </Pallet>
</Pallets>

关键修复点说明

  1. 修正Pallet循环逻辑:将Pallet = Pallet.nextSiblingElement();移到外层while循环内部,确保能遍历所有Pallet节点。
  2. 修复子节点遍历顺序:遍历Box/Cylinder的子节点时,使用当前节点的nextSiblingElement()而非初始的Code节点,保证节点顺序正确。
  3. 数值转字符串初始化Item:所有数值类型的QStandardItem都用QString::number()转换后创建,避免将数值当作角色值误用。
  4. 关联TableView与Model:在构造函数中添加ContainerView->setModel(HMod);,让表格能显示解析后的数据。
  5. 避免空指针访问:在updateRow中先判断节点指针是否有效,遍历列时也检查Item是否存在,防止程序崩溃。
  6. 新增XML解析校验:调用setContent后检查是否解析成功,便于排查XML格式问题。

内容的提问来源于stack exchange,提问作者Martin Sieburg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:06:30