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

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()的返回值,端口绑定失败、数据发送目标错误都没有任何日志提示,很难快速定位问题。
修复方案
  1. 删掉冗余的全局Server实例,只保留一个UDP通信实例即可,避免端口冲突。
  2. 把发送目标地址改成STM32设备的实际IP和端口,参数和你用hercules测试时填写的STM32目标参数完全一致即可。
  3. 绑定端口时建议用QHostAddress::Any监听所有网卡地址,同时增加绑定结果校验,失败时打印错误日志。
  4. 接收数据时增加循环读取逻辑,避免多个数据包同时到达时出现丢包。

修复后代码参考

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 03:42:30