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);
    }
}
相关推荐
hsjkdhs1 小时前
万字详解C++之构造函数析构函数
开发语言·c++
Lin_Aries_04212 小时前
容器化简单的 Java 应用程序
java·linux·运维·开发语言·docker·容器·rpc
SELSL2 小时前
SQLite3的API调用实战例子
linux·数据库·c++·sqlite3·sqlite实战
什么半岛铁盒2 小时前
C++项目:仿muduo库高并发服务器-------Channel模块实现
linux·服务器·数据库·c++·mysql·ubuntu
techdashen2 小时前
12分钟讲解Python核心理念
开发语言·python
闭着眼睛学算法3 小时前
【华为OD机考正在更新】2025年双机位A卷真题【完全原创题解 | 详细考点分类 | 不断更新题目 | 六种主流语言Py+Java+Cpp+C+Js+Go】
java·c语言·javascript·c++·python·算法·华为od
山海不说话3 小时前
Java后端面经(八股——Redis)
java·开发语言·redis
小白银子3 小时前
零基础从头教学Linux(Day 42)
linux·运维·服务器·网络·nginx
郝学胜-神的一滴3 小时前
谨慎地迭代函数所收到的参数 (Effective Python 第31条)
开发语言·python·程序人生·软件工程
ShineSpark3 小时前
C++面试11——指针与引用
c++·面试