Qt UDP Socket的具体使用
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
#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 的 QUdpSocket 和 QNetworkDatagram 类为UDP网络编程提供了简洁而强大的封装。通过它们,开发者可以快速实现基于UDP的通信功能,适用于实时性高、允许丢包的场景。尽管UDP本身不可靠,但结合适当的应用层协议设计,仍可构建稳定高效的网络应用。
Qt Network模块的跨平台特性使得同一套代码可在Windows、Linux、macOS等系统中运行,极大提升了开发效率。在实际项目中,若需更可靠的通信,可考虑使用TCP;若追求低延迟和高实时性,UDP则是更佳选择。
到此这篇关于Qt UDP Socket的具体使用的文章就介绍到这了,更多相关Qt UDP Socket内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
codeblocks 对‘cv::waitKey(int)’未定义的引用方式
今天小编就为大家分享一篇codeblocks 对‘cv::waitKey(int)’未定义的引用方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2019-12-12


最新评论