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

