QT QUdpSocket可发送UDP包但无法接收数据readyRead槽不触发
问题现象
STM32设备可与hercules_3-2-8工具正常收发UDP数据包,基于Qt编写的测试程序可正常发送UDP数据包,但无法接收到任何回包,readyRead槽函数始终不触发。
原MyUDP类实现
MyUDP::MyUDP(QObject *parent) : QObject(parent) { socket = new QUdpSocket(this); socket->bind(QHostAddress("192.168.1.100"),2000); connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); } void MyUDP::SayHello(){ QByteArray Data; Data.append("Hello from ASiDesigner"); socket->writeDatagram(Data,QHostAddress("192.168.1.100"),2000); qDebug()<<"Hi Nitrogen"; } void MyUDP::readyRead(){ QByteArray Buffer; Buffer.resize((socket->pendingDatagramSize())); QHostAddress sender; quint16 senderPort; socket->readDatagram(Buffer.data(),Buffer.size(),&sender,&senderPort); qDebug()<<"Message from: "<<sender.toString(); qDebug()<<"Message port: "<<senderPort; qDebug()<<"Message: "<<Buffer; }
原mainwindow.cpp实现
#include "mainwindow.h" #include "ui_mainwindow.h" #include "myudp.h" MyUDP Server; MyUDP client; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { client.SayHello(); }
问题根因
代码存在4处核心问题,直接导致无法接收STM32的回包:
- 发送目标地址完全错误:
SayHello()方法中写死的发送目标是192.168.1.100:2000,这是运行Qt程序的PC本机IP,不是STM32设备的IP。数据包从PC发出后直接回到PC本机的2000端口,STM32根本收不到任何数据,自然不会返回响应包。 - 重复绑定端口导致绑定失败:全局定义了
Server、client两个MyUDP实例,两个实例构造时都会尝试绑定192.168.1.100:2000端口。先构造的Server会绑定成功,后构造的client绑定同地址同端口会直接失败(Qt默认不允许同端口重复绑定),client实际没有监听2000端口。 - 冗余实例占用端口:全局的
Server实例没有任何业务逻辑调用,白白占用2000端口,没有实际作用。 - 缺少错误校验:代码没有检查
bind()、writeDatagram()的返回值,端口绑定失败、数据发送目标错误都没有任何日志提示,很难快速定位问题。
修复方案
- 删掉冗余的全局
Server实例,只保留一个UDP通信实例即可,避免端口冲突。 - 把发送目标地址改成STM32设备的实际IP和端口,参数和你用hercules测试时填写的STM32目标参数完全一致即可。
- 绑定端口时建议用
QHostAddress::Any监听所有网卡地址,同时增加绑定结果校验,失败时打印错误日志。 - 接收数据时增加循环读取逻辑,避免多个数据包同时到达时出现丢包。
修复后代码参考
myudp.cpp修改
MyUDP::MyUDP(QObject *parent) : QObject(parent) { socket = new QUdpSocket(this); // 绑定所有网卡的2000端口,增加错误校验 bool bindOk = socket->bind(QHostAddress::Any, 2000); if (!bindOk) { qDebug() << "UDP端口绑定失败:" << socket->errorString(); return; } connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); } void MyUDP::SayHello(){ QByteArray Data; Data.append("Hello from ASiDesigner"); // 替换为STM32的实际IP和监听端口,与hercules测试参数保持一致 QHostAddress stm32Ip("192.168.1.xxx"); quint16 stm32Port = 2000; socket->writeDatagram(Data, stm32Ip, stm32Port); qDebug()<<"Hi Nitrogen"; } void MyUDP::readyRead(){ // 循环读取缓冲区所有待处理数据包,避免丢包 while (socket->hasPendingDatagrams()) { QByteArray Buffer; Buffer.resize(socket->pendingDatagramSize()); QHostAddress sender; quint16 senderPort; socket->readDatagram(Buffer.data(), Buffer.size(), &sender, &senderPort); qDebug()<<"Message from: "<<sender.toString(); qDebug()<<"Message port: "<<senderPort; qDebug()<<"Message: "<<Buffer; } }
mainwindow.cpp修改
#include "mainwindow.h" #include "ui_mainwindow.h" #include "myudp.h" // 仅保留一个通信实例 MyUDP client; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { client.SayHello(); }
额外排查点
如果修改后仍无法接收数据,按以下顺序排查:
- 临时关闭系统防火墙、第三方杀毒软件,避免UDP数据包被拦截
- 确认PC和STM32在同一网段,PC端可正常ping通STM32的IP
- 先用hercules在PC上监听2000端口,确认STM32会主动往PC的2000端口发包
- 确认STM32固件中配置的目标回包IP是PC当前的实际IP,不是之前hercules测试时的旧配置
内容的提问来源于stack exchange,提问作者ASiDesigner
相关产品推荐
相关产品推荐

