文章目录
- [1 -> 概述](#1 -> 概述)
- [2 -> Qt UDP Socket 核心类](#2 -> Qt UDP Socket 核心类)
-
- [2.1 -> `QUdpSocket`](#2.1 ->
QUdpSocket) - [2.2 -> `QNetworkDatagram`](#2.2 ->
QNetworkDatagram)
- [2.1 -> `QUdpSocket`](#2.1 ->
- [3 -> 核心API详解](#3 -> 核心API详解)
-
- [3.1 -> `QUdpSocket` 类的主要方法](#3.1 ->
QUdpSocket类的主要方法) -
- [3.1.1 -> `bind(const QHostAddress &address, quint16 port)`](#3.1.1 ->
bind(const QHostAddress &address, quint16 port)) - [3.1.2 -> `receiveDatagram()`](#3.1.2 ->
receiveDatagram()) - [3.1.3 -> `writeDatagram(const QNetworkDatagram &datagram)`](#3.1.3 ->
writeDatagram(const QNetworkDatagram &datagram)) - [3.1.4 -> `readyRead` 信号](#3.1.4 ->
readyRead信号)
- [3.1.1 -> `bind(const QHostAddress &address, quint16 port)`](#3.1.1 ->
- [3.2 -> `QNetworkDatagram` 类的主要方法](#3.2 ->
QNetworkDatagram类的主要方法) -
- [3.2.1 -> 构造函数 `QNetworkDatagram(const QByteArray &data, const QHostAddress &address, quint16 port)`](#3.2.1 -> 构造函数
QNetworkDatagram(const QByteArray &data, const QHostAddress &address, quint16 port)) - [3.2.2 -> `data()`](#3.2.2 ->
data()) - [3.2.3 -> `senderAddress()` 和 `senderPort()`](#3.2.3 ->
senderAddress()和senderPort()) - [3.2.4 -> `destinationAddress()` 和 `destinationPort()`](#3.2.4 ->
destinationAddress()和destinationPort())
- [3.2.1 -> 构造函数 `QNetworkDatagram(const QByteArray &data, const QHostAddress &address, quint16 port)`](#3.2.1 -> 构造函数
- [3.1 -> `QUdpSocket` 类的主要方法](#3.1 ->
- [4 -> UDP Socket 工作流程简述](#4 -> UDP Socket 工作流程简述)
- [5 -> 注意事项](#5 -> 注意事项)
- [6 -> 代码示例](#6 -> 代码示例)
-
- [6.1 -> 回显服务端](#6.1 -> 回显服务端)
- [6.2 -> 回显客户端](#6.2 -> 回显客户端)
- [7 -> 总结](#7 -> 总结)

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 工作流程简述
-
创建与绑定:
- 创建
QUdpSocket对象。 - 调用
bind()绑定本地地址和端口。
- 创建
-
接收数据:
- 连接
readyRead信号到自定义槽函数。 - 在槽函数中调用
receiveDatagram()获取数据报。
- 连接
-
发送数据:
- 构造
QNetworkDatagram对象,填入数据、目标地址和端口。 - 调用
writeDatagram()发送。
- 构造
-
错误处理:
- 可通过
error()和errorString()获取错误信息。 - 建议在关键操作后检查返回值。
- 可通过
5 -> 注意事项
- 数据报大小限制:UDP数据报大小通常不超过64KB(包括IP头部),实际应用中建议控制在1500字节以内以避免分片。
- 无序与丢包:UDP不保证数据顺序和可靠性,需在应用层实现必要的确认、重传或排序机制。
- 多播与广播 :
QUdpSocket支持多播和广播,可通过joinMulticastGroup()等方法实现。 - 线程安全:Qt网络类通常建议在同一线程中使用,跨线程访问需谨慎处理。
6 -> 代码示例
6.1 -> 回显服务端
widget.cpp
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
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 的 QUdpSocket 和 QNetworkDatagram 类为UDP网络编程提供了简洁而强大的封装。通过它们,开发者可以快速实现基于UDP的通信功能,适用于实时性高、允许丢包的场景。尽管UDP本身不可靠,但结合适当的应用层协议设计,仍可构建稳定高效的网络应用。
Qt Network模块的跨平台特性使得同一套代码可在Windows、Linux、macOS等系统中运行,极大提升了开发效率。在实际项目中,若需更可靠的通信,可考虑使用TCP;若追求低延迟和高实时性,UDP则是更佳选择。
感谢各位大佬支持!!!
互三啦!!!