Qt UDP Socket的具体使用

 更新时间:2026年01月20日 08:25:38   作者:枫叶丹4  
本文介绍了Qt框架中基于UDP协议的网络通信实现,UDP是一种无连接、高效但不可靠的传输协议,适合实时性要求高的应用场景,具有一定的参考价值,感兴趣的可以了解一下

1 -> 概述

UDP(User Datagram Protocol,用户数据报协议)是一种无连接的、不可靠但高效的数据传输协议。它不保证数据包的顺序、完整性或可达性,但由于没有建立连接和确认机制,传输速度较快,适合实时性要求高、允许少量丢包的应用场景,如音视频流、在线游戏、DNS查询等。

Qt 作为一个跨平台的C++应用程序框架,对网络编程提供了良好的封装。Qt Network 模块中的 QUdpSocket 类提供了UDP协议的网络通信能力,使开发者能够轻松实现基于UDP的数据收发功能。

2 -> Qt UDP Socket 核心类

在Qt中实现UDP通信主要涉及两个核心类:

2.1 ->QUdpSocket

  • 表示一个UDP socket,用于绑定端口、接收和发送数据报。
  • 继承自 QAbstractSocket,属于Qt Network模块。
  • 支持IPv4和IPv6。

2.2 ->QNetworkDatagram

  • 表示一个UDP数据报,封装了数据内容、发送/接收方的IP地址和端口信息。
  • 提供了便捷的方法来获取和构造数据报。

3 -> 核心API详解

3.1 ->QUdpSocket类的主要方法

3.1.1 ->bind(const QHostAddress &address, quint16 port)

  • 功能:将socket绑定到指定的IP地址和端口。
  • 参数
    • address:绑定的IP地址,如 QHostAddress::Any 表示绑定到所有可用地址。
    • port:绑定的端口号。
  • 返回值:布尔类型,表示绑定是否成功。
  • 说明:绑定后,socket开始监听该端口的数据报。

3.1.2 ->receiveDatagram()

  • 功能:接收一个UDP数据报。
  • 返回值QNetworkDatagram 对象,包含接收到的数据、发送方地址和端口。
  • 说明:通常与 readyRead 信号配合使用,在数据可读时调用。

3.1.3 ->writeDatagram(const QNetworkDatagram &datagram)

  • 功能:发送一个UDP数据报。
  • 参数QNetworkDatagram 对象,包含要发送的数据、目标地址和端口。
  • 返回值:发送的字节数,若出错返回-1。

3.1.4 ->readyRead信号

  • 触发时机:当socket接收到数据并准备好读取时发出。
  • 用途:通常连接到一个槽函数,在该函数中调用 receiveDatagram() 处理数据。

3.2 ->QNetworkDatagram类的主要方法

3.2.1 -> 构造函数QNetworkDatagram(const QByteArray &data, const QHostAddress &address, quint16 port)

  • 功能:构造一个用于发送的数据报。
  • 参数
    • data:要发送的数据。
    • address:目标IP地址。
    • port:目标端口。

3.2.2 ->data()

  • 功能:获取数据报中的数据内容。
  • 返回值QByteArray 类型。

3.2.3 ->senderAddress()和senderPort()

  • 功能:获取发送该数据报的源IP地址和端口。
  • 说明:适用于接收到的数据报,用于识别发送方。

3.2.4 ->destinationAddress()和destinationPort()

  • 功能:获取数据报的目标地址和端口。
  • 说明:适用于发送或接收的数据报。

4 -> UDP Socket 工作流程简述

  1. 创建与绑定

    • 创建 QUdpSocket 对象。
    • 调用 bind() 绑定本地地址和端口。
  2. 接收数据

    • 连接 readyRead 信号到自定义槽函数。
    • 在槽函数中调用 receiveDatagram() 获取数据报。
  3. 发送数据

    • 构造 QNetworkDatagram 对象,填入数据、目标地址和端口。
    • 调用 writeDatagram() 发送。
  4. 错误处理

    • 可通过 error()errorString() 获取错误信息。
    • 建议在关键操作后检查返回值。

5 -> 注意事项

  • 数据报大小限制:UDP数据报大小通常不超过64KB(包括IP头部),实际应用中建议控制在1500字节以内以避免分片。
  • 无序与丢包:UDP不保证数据顺序和可靠性,需在应用层实现必要的确认、重传或排序机制。
  • 多播与广播QUdpSocket 支持多播和广播,可通过 joinMulticastGroup() 等方法实现。
  • 线程安全:Qt网络类通常建议在同一线程中使用,跨线程访问需谨慎处理。

6 -> 代码示例

6.1 -> 回显服务端

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QMessageBox>
#include <QNetworkDatagram>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 创建对象
    socket = new QUdpSocket(this);

    // 设置窗口标题
    this->setWindowTitle("服务器");

    // 连接信号槽
    connect(socket, &QUdpSocket::readyRead, this, &Widget::processRequest);

    // 绑定端口号
    bool ret = socket->bind(QHostAddress::Any, 9090);
    if (!ret)
    {
        QMessageBox::critical(this, "服务器启动出错", socket->errorString());
        return;
    }


}

Widget::~Widget()
{
    delete ui;
}

void Widget::processRequest()
{
    // 1. 读取请求并解析
    const QNetworkDatagram& requestDatagram = socket->receiveDatagram();
    QString request = requestDatagram.data();

    // 2. 根据请求计算响应. (由于是回显服务器. 响应不需要计算, 就是请求本身)
    const QString& response = process(request);

    // 3. 把响应写回给客户端
    QNetworkDatagram responseDatagram(response.toUtf8(), requestDatagram.senderAddress(), requestDatagram.senderPort());
    socket->writeDatagram(responseDatagram);

    // 把这次交互的信息, 显示到界面上
    QString log = "[" + requestDatagram.senderAddress().toString() + QString::number(requestDatagram.senderPort())
             + "]" + "req: " + request + "resp: " + response;
    ui->listWidget->addItem(log);

}

QString Widget::process(const QString &request)
{
    // 由于当前是回显服务器, 响应就是和请求完全一样
   // 对于一个成熟的商业服务器, 这里请求->响应的计算过程可能是非常复杂的(业务逻辑)
   return request;
}


6.2 -> 回显客户端

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <QNetworkDatagram>

// 定义两个常量, 描述服务器的 地址 和 端口
const QString& SERVER_IP = "127.0.0.1";
const quint16 SERVER_PORT = 9090;

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    socket = new QUdpSocket(this);

    // 修改窗口标题
    this->setWindowTitle("客户端");

    // 通过信号槽, 来处理服务器返回的数据
    connect(socket, &QUdpSocket::readyRead, this, &Widget::processResponse);
}

Widget::~Widget()
{
    delete ui;
}


void Widget::on_pushButton_clicked()
{
    // 1. 获取到输入框的内容
    QString text = ui->lineEdit->text();

    // 2. 构造 UDP 的请求数据
    QNetworkDatagram requestDatagram(text.toUtf8(), QHostAddress(SERVER_IP), SERVER_PORT);

    // 3. 发送请求数据
    socket->writeDatagram(requestDatagram);

    // 4. 把发送的请求也添加到列表框中
    ui->listWidget->addItem("客户端说: " + text);

    // 5. 清空输入框
    ui->lineEdit->setText("");

}

void Widget::processResponse()
{
    // 通过这个函数来处理收到的响应.
    // 1. 读取到响应数据
    const QNetworkDatagram responseDatagram = socket->receiveDatagram();
    QString response = responseDatagram.data();

    // 2. 把响应数据显示到界面上
    ui->listWidget->addItem("服务器说: " + response);
}

7 -> 总结

Qt 的 QUdpSocketQNetworkDatagram 类为UDP网络编程提供了简洁而强大的封装。通过它们,开发者可以快速实现基于UDP的通信功能,适用于实时性高、允许丢包的场景。尽管UDP本身不可靠,但结合适当的应用层协议设计,仍可构建稳定高效的网络应用。

Qt Network模块的跨平台特性使得同一套代码可在Windows、Linux、macOS等系统中运行,极大提升了开发效率。在实际项目中,若需更可靠的通信,可考虑使用TCP;若追求低延迟和高实时性,UDP则是更佳选择。

到此这篇关于Qt UDP Socket的具体使用的文章就介绍到这了,更多相关Qt UDP Socket内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现随机发牌

    C语言实现随机发牌

    这篇文章主要为大家详细介绍了C语言实现随机发牌,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C++实现LeetCode(168.求Excel表列名称)

    C++实现LeetCode(168.求Excel表列名称)

    这篇文章主要介绍了C++实现LeetCode(168.求Excel表列名称),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • codeblocks 对‘cv::waitKey(int)’未定义的引用方式

    codeblocks 对‘cv::waitKey(int)’未定义的引用方式

    今天小编就为大家分享一篇codeblocks 对‘cv::waitKey(int)’未定义的引用方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-12-12
  • VS2019实现C++的第一个MFC程序

    VS2019实现C++的第一个MFC程序

    本文主要介绍了VS2019实现C++的第一个MFC程序,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-06-06
  • C++中的HTTP协议问题

    C++中的HTTP协议问题

    这篇文章主要介绍了C++中的HTTP协议问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • QT5实现简单的TCP通信的实现

    QT5实现简单的TCP通信的实现

    本文主要介绍了QT5实现简单的TCP通信的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • opencv 做人脸识别 opencv 人脸匹配分析

    opencv 做人脸识别 opencv 人脸匹配分析

    opencv 人脸识别通过级联分类器对特征的分级筛选来确定是否是人脸,每个节点的正确识别率很高,但正确拒绝率很低,任一节点判断没有人脸特征则结束运算,宣布不是人脸
    2012-11-11
  • 基于list循环删除元素,迭代器失效的问题详解

    基于list循环删除元素,迭代器失效的问题详解

    下面小编就为大家带来一篇基于list循环删除元素,迭代器失效的问题详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • 详解C语言中二级指针与链表的应用

    详解C语言中二级指针与链表的应用

    对于初学者而言,有很多地方肯定是费解的。比如函数的参数列表的多样化,动态分配内存空间函数malloc等,其实这些知识和指针联系紧密,尤其是二级指针,快跟随小编来学习一下吧
    2022-07-07
  • C语言进阶:指针的进阶(4)

    C语言进阶:指针的进阶(4)

    这篇文章主要介绍了C语言指针详解及用法示例,介绍了其相关概念,然后分享了几种用法,具有一定参考价值。需要的朋友可以了解下
    2021-09-09

最新评论