Qt UDP 通信类详解与实现

这是一个基于 Qt 框架的 UDP 通信类实现,用于处理 UDP 数据包的发送和接收。下面是对这个代码的详细介绍:

功能概述

这个 UDPCommunication 类提供了以下核心功能:

  • 发送 UDP 数据包到指定地址和端口
  • 监听指定端口接收 UDP 数据
  • 发送特定格式的监控数据(01 0A 55)
  • 处理通信错误和异常情况

类结构详解

公共方法

  1. 构造函数/析构函数:初始化/清理 UDP socket
  2. sendUdpData():发送原始数据到指定地址和端口
  3. startListening():在指定端口开始监听
  4. stopListening():停止监听
  5. sendMonitoringData():发送预设的监控数据(01 0A 55)

信号

  1. dataReceived():当接收到数据时发出,包含数据内容和发送方信息
  2. errorOccurred():发生错误时发出,包含错误信息

私有槽函数

  • onReadyRead():处理接收到的数据

成员变量

  • udpSocket:QUdpSocket 实例,用于实际的 UDP 通信
  • listeningPort:当前监听的端口号

核心功能实现

数据发送

cpp 复制代码
bool sendUdpData(const QHostAddress &address, quint16 port, const QByteArray &data);

使用 writeDatagram() 方法发送数据,并检查发送结果。

数据接收

通过连接 QUdpSocket::readyRead 信号到 onReadyRead() 槽函数,在有数据到达时自动处理。

端口监听

cpp 复制代码
bool startListening(quint16 port);

使用 bind() 方法绑定到指定端口开始监听。

错误处理

通过连接 errorOccurred 信号来捕获和处理 socket 错误。

使用示例

cpp 复制代码
// 创建实例
UDPCommunication udp;

// 开始监听端口 4000
udp.startListening(4000);

// 发送数据到目标设备
QByteArray data = "Hello UDP";
udp.sendUdpData(QHostAddress("192.168.1.100"), 4010, data);

// 发送预设的监控数据
udp.sendMonitoringData(QHostAddress("192.168.1.100"), 4010);

// 连接信号处理接收到的数据
connect(&udp, &UDPCommunication::dataReceived, [](const QByteArray &data, const QHostAddress &sender, quint16 port) {
    qDebug() << "Received from" << sender.toString() << ":" << data;
});

特点

  1. 封装良好:将复杂的 UDP socket 操作封装成简单易用的接口
  2. 错误处理完善:提供详细的错误信息和异常处理
  3. 线程安全:基于 Qt 的信号槽机制,适合多线程环境
  4. 灵活性强:支持任意数据的发送和接收
  5. 调试友好:包含详细的调试输出

适用场景

  • 网络设备监控和控制
  • 实时数据采集系统
  • 分布式系统间的轻量级通信
  • 需要简单可靠 UDP 通信的各种应用

这个类提供了一个完整且健壮的 UDP 通信解决方案,可以直接集成到 Qt 项目中使用。

完整代码

UDPCommunication.h

cpp 复制代码
#ifndef UDPCOMMUNICATION_H
#define UDPCOMMUNICATION_H

#include <QObject>
#include <QUdpSocket>
#include <QByteArray>
#include <QHostAddress>

class UDPCommunication : public QObject
{
    Q_OBJECT
public:
    explicit UDPCommunication(QObject *parent = nullptr);
    ~UDPCommunication();

    // 发送 UDP 数据包
    bool sendUdpData(const QHostAddress &address, quint16 port, const QByteArray &data);

    // 开始监听指定端口接收数据
    bool startListening(quint16 port);

    // 停止监听
    void stopListening();

    // 便捷方法:发送特定格式的数据到指定地址和端口
    bool sendMonitoringData(const QHostAddress &address = QHostAddress("192.168.0.119"),
                            quint16 port = 4010);

signals:
    // 当接收到数据时发出信号
    void dataReceived(const QByteArray &data, const QHostAddress &sender, quint16 port);

    // 当发生错误时发出信号
    void errorOccurred(const QString &errorString);

private slots:
    // 处理接收到的数据
    void onReadyRead();

private:
    QUdpSocket *udpSocket;
    quint16 listeningPort;
};


#endif // UDPCOMMUNICATION_H

UDPCommunication.cpp

cpp 复制代码
#include "UDPCommunication.h"
#include <QDebug>

UDPCommunication::UDPCommunication(QObject *parent)
    : QObject(parent), udpSocket(nullptr), listeningPort(0)
{
    udpSocket = new QUdpSocket(this);
    connect(udpSocket, &QUdpSocket::readyRead, this, &UDPCommunication::onReadyRead);
    connect(udpSocket, QOverload<QUdpSocket::SocketError>::of(&QUdpSocket::errorOccurred),
            [this](QUdpSocket::SocketError error) {
                emit errorOccurred(udpSocket->errorString());
            });
}

UDPCommunication::~UDPCommunication()
{
    stopListening();
}

bool UDPCommunication::sendUdpData(const QHostAddress &address, quint16 port, const QByteArray &data)
{
    if (!udpSocket) {
        emit errorOccurred("UDP socket is not initialized");
        return false;
    }

    qint64 bytesSent = udpSocket->writeDatagram(data, address, port);
    if (bytesSent == -1) {
        emit errorOccurred(udpSocket->errorString());
        return false;
    }

    qDebug() << "Sent" << bytesSent << "bytes to" << address.toString() << ":" << port;
    return true;
}

bool UDPCommunication::startListening(quint16 port)
{
    if (!udpSocket) {
        emit errorOccurred("UDP socket is not initialized");
        return false;
    }

    if (udpSocket->state() == QAbstractSocket::BoundState) {
        udpSocket->close();
    }

    if (udpSocket->bind(port)) {
        listeningPort = port;
        qDebug() << "Started listening on port" << port;
        return true;
    } else {
        emit errorOccurred(udpSocket->errorString());
        return false;
    }
}

void UDPCommunication::stopListening()
{
    if (udpSocket && udpSocket->state() == QAbstractSocket::BoundState) {
        udpSocket->close();
        listeningPort = 0;
        qDebug() << "Stopped listening";
    }
}

bool UDPCommunication::sendMonitoringData(const QHostAddress &address, quint16 port)
{
    // 创建要发送的数据:01 0A 55
    QByteArray data;
    data.append(0x01);
    data.append(0x0A);
    data.append(0x55);

    return sendUdpData(address, port, data);
}

void UDPCommunication::onReadyRead()
{
    if (!udpSocket) return;

    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        qint64 bytesRead = udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        if (bytesRead == -1) {
            emit errorOccurred(udpSocket->errorString());
            continue;
        }

        qDebug() << "Received" << bytesRead << "bytes from" << sender.toString() << ":" << senderPort;
        emit dataReceived(datagram, sender, senderPort);
    }
}
相关推荐
pusue_the_sun3 小时前
C语言强化训练(12)
c语言·开发语言·算法
君鼎3 小时前
More Effective C++ 条款29:引用计数
c++
小欣加油3 小时前
leetcode 6 Z字形变化
c++·算法·leetcode·职场和发展
曙曙学编程3 小时前
stm32——寄存器操作,蜂鸣器原理
c语言·c++·stm32·单片机·嵌入式硬件
Jayyih3 小时前
嵌入式系统学习Day29(tcp)
网络·学习·tcp/ip
dog2503 小时前
乐观并发: TCP 与编程实践
网络·网络协议·tcp/ip
MoloXuanhe3 小时前
[TryHackMe]Wordpress: CVE-2021-29447(wp漏洞利用-SSRF+WpGetShell)
运维·网络·安全·tryhackme·thm
wanhengidc3 小时前
网页版的云手机都有哪些优势?
运维·网络·安全·游戏·智能手机
counting money4 小时前
JAVA泛型基础
java·开发语言·eclipse