问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Qt学习笔记之UDP通信

创作时间:
作者:
@小白创作中心

Qt学习笔记之UDP通信

引用
CSDN
1.
https://blog.csdn.net/Yz12333/article/details/138013152

本文将详细介绍如何使用Qt框架实现UDP通信。文章首先对比了TCP和UDP通信的主要区别,然后通过具体步骤展示了如何创建UDP工程、设置UI界面,并提供了完整的代码示例来说明如何实现UDP通信的各项功能。

一、UDP通信

使用Qt来实现TCP和UDP通信时,虽然基本的编程概念相似,但是由于两种协议本身的特点,实现方式和使用场景会有所不同。

1. 通信方式:

TCP:Qt中使用QTcpServer和QTcpSocket两个类来实现基于TCP的通信。QTcpServer用于创建服务器端应用程序,而QTcpSocket既可以用于创建客户端。TCP是面向连接的,所以在使用QTcpSocket时,需要先调用connectToHost方法来建立连接,然后才能发送和接收数据。连接建立后,数据传输是双向的,可以同时进行发送和接收。所以在TCP通信的中我们不仅实现了TCP客户端还实现了TCP服务器。

UDP:Qt中使用QUdpSocket一个类来实现基于UDP的通信。UDP是无连接的,使用QUdpSocket时可以直接发送数据,不需要建立连接。发送和接收数据是独立的操作,发送数据使用write方法,接收数据则是通过信号readyRead来处理。所以UDP通信实现起来更加容易,UDP不分客户端和服务器,只需要创建一个工程即可。

2. 数据流与数据报:

TCP:QTcpSocket处理的是面向流的数据,数据在发送和接收时是以连续的字节流形式进行的,没有明确的数据边界。

UDP:QUdpSocket处理的是数据报,每个发送和接收的数据单元都是独立的,具有明确的边界。这使得UDP在处理某些需要独立数据包的应用时更为方便。

3. 可靠性与效率:

TCP:使用QTcpSocket时,Qt会自动处理数据的可靠性,包括数据的顺序、完整性和重传机制。这使得TCP通信更加稳定,但也意味着会有更多的开销。

UDP:使用QUdpSocket时,开发者需要自己处理数据的顺序和完整性。UDP通信效率更高,但可能会有丢包的情况发生。

4. 错误处理:

TCP:QTcpSocket提供了一些错误信号,如disconnected、error等,可以用来处理连接断开或通信错误的情况。

UDP:QUdpSocket同样提供了error信号,但由于UDP的特性,错误处理通常更加简单,主要是处理无法发送或接收数据的情况。

示例代码:

①TCP示例:

QTcpSocket *socket = new QTcpSocket(this);
socket->connectToHost("server.example.com", 1234);
connect(socket, &QTcpSocket::readyRead, this, &MyClass::onReadyRead);
socket->write("Hello, Server!");

②UDP示例:

QUdpSocket *socket = new QUdpSocket(this);
socket->bind(QHostAddress::Any, 1234);
connect(socket, &QUdpSocket::readyRead, this, &MyClass::onReadyRead);
socket->writeDatagram("Hello, Server!", QHostAddress("server.example.com"), 1234);

在使用Qt进行网络编程时,选择TCP还是UDP主要取决于应用的需求。如果需要可靠的数据传输和流式处理,TCP是更好的选择;如果对实时性要求较高,可以容忍一定程度的数据丢失,并且希望避免建立连接的开销,那么UDP可能更适合。Qt提供了丰富的类和方法来支持这两种协议的实现,开发者可以根据具体情况灵活选择。

二、创建UDP工程(与TCP工程步骤一致)

第一步:打开QT软件,新建工程;
第二步:选择一个模板(默认即可);
第三步:设置项目名称以及项目存储路径;
第四步:编译器选择(默认即可)
第五步:基类选择(QWidget)
第六步:项目管理(默认即可)
第七步:生成工程
第八步:编译验证(Ctrl + R如图所示,创建工程成功)

三、设置UI界面

第一步:双击Forms文件下的widget.ui文件

第二步:设置UI界面
以接收框为例,步骤如下:

UI界面设置包含下面7步:

  1. 接收框:Plain Text Edit控件(重命名:receiveEdit)
  2. 发送框:Line Edit控件(重命名:sendEdit)
  3. 接收窗口和发送窗口:Group Box控件
  4. 本地端口框:Line Edit(重命名:localPort) + Label控件
  5. 目标端口框:Line Edit(重命名:aimPort) + Label控件
  6. 目标IP框:Line Edit(重命名:aimIp) + Label控件
  7. 按钮:PushButton 控件:
    打开(重命名:openBt)、关闭(重命名:closeBt)、发送(重命名:sendBt)

最后设置编译运行效果如下:

四、新类的使用(QUdpSocket Class)

步骤:帮助->索引->搜索“QUdpSocket类”
下滑可查看使用示例:

  1. 在widget.h文件中,添加所用头文件:#include
  2. 在.pro文件中,添加network;
  3. 在widget.h文件中,定义指针变量,用于创建和操作UDP;
    4.在widget.cpp文件中的构造函数中,使用new关键字,为指针变量分配内存,初始化指针。

五、功能实现逻辑代码编写

UDP所需要实现的功能:
①打开UDP,并绑定本地端口号;
②连接信号,接收数据,并在接收窗口显示数据;
③发送数据至指定的地址和端口;
④关闭UDP。

1. 打开UDP,并绑定本地端口号

第一步:关联“打开按钮控件”信号和槽(自动关联);

第二步:编写代码,绑定本地端口号;

注释:在Qt中,调用udpSocket->bind(ui->localPort->text().toUInt());这行代码的目的是将QUdpSocket对象绑定到由用户通过UI界面(比如一个文本输入框QLineEdit)指定的端口上。这里的ui是一个指向Ui::类名的指针,它是一个由Qt的UI编译器自动生成的类,包含了你在Qt Designer中设计的用户界面的所有部件。

  1. ui->localPort:这通常是一个指向QLineEdit或类似文本输入控件的指针,它允许用户输入数据。
  2. ->text():这是对QLineEdit或文本输入控件的成员函数调用,用于获取用户输入的文本。
  3. .toUInt():这是一个将QString对象(用户输入的文本)转换为unsignedint(无符号整数)的方法。这里使用toUInt()是因为它期望端口号是一个非负整数,而端口号的范围是从0到65535。
  4. udpSocket->bind():这是QUdpSocket类的成员函数,用于将UDP套接字绑定到一个特定的端口上。绑定后,套接字就可以接收发送到该端口的UDP数据报了。

将这些组合起来,udpSocket->bind(ui->localPort->text().toUInt());这行代码的作用是将UDP套接字绑定到用户在ui->localPort控件中输入的端口号上。如果用户输入了一个有效的端口号,UDP套接字将监听该端口的入站数据报。

第三步:增加提示功能

2. 连接信号,接收数据,并在接收窗口显示数据(同理于TCP的槽函数编写,手动关联)

第一步:连接信号:connect(udpSocket, SIGNAL(readyRead()),this, SLOT(readyRead_Slot()));

第二步:在widget.h文件中定义槽函数:void readyRead_Slot();

第三步:在widget.cpp文件中编写槽函数void Widget::readyRead_Slot()代码

注释:上述代码是在Qt应用程序中使用QUdpSocket来接收UDP数据报,并将接收到的数据展示在用户界面上。readyRead_Slot函数是与QUdpSocket的readyRead信号连接的槽函数。当QUdpSocket可读时,即当它接收到新的UDP数据报时,该槽函数会被调用。

1.while(udpSocket->hasPendingDatagrams())循环用于读取所有待处理的数据报。这是因为在某些情况下,可能同时接收到多个数据报。
2.QByteArrayarray;创建一个QByteArray对象用于存储接收到的数据。
3.array.resize(udpSocket->pendingDatagramSize());调整QByteArray的大小以匹配即将读取的数据报的大小。
4.udpSocket->readDatagram(array.data(),array.size());从QUdpSocket读取一个数据报到QByteArray。

5.QStringbuff;创建一个QString对象。
6.buff=array.data();将QByteArray转换为QString。
7. ui->receiveEdit->appendPlainText(buff);将接收到的数据追加到用户界面的文本编辑器中。

第四步:运行程序

第五步:验证接收数据效果(与网络调试助手联调)

如上述所示,已可以正常接收调试助手发送的数据。

3. 发送数据至指定的地址和端口

第一步:关联“发送按钮控件”信号和槽(自动关联);

第二步:编写代码,将(ui->sendEdit)控件输入的数据发送给指定的地址和端口;

注释:上述代码是一个Qt槽函数on_sendBt_clicked,它在用户点击发送按钮时被触发,用于发送UDP数据报。on_sendBt_clicked函数处理发送UDP数据报的逻辑:

  1. address.setAddress(ui->aimIp->text());:获取用户在UI组件中输入的目标IP地址,并将该地址设置为QHostAddress对象。
  2. sendbuff=ui->sendEdit->text();:获取用户在发送文本编辑器中输入的字符串,这将作为UDP数据报的内容。
  3. port=ui->aimPort->text().toUInt();:获取用户输入的目标端口号,并转换为无符号整数。
    4.udpSocket->writeDatagram(sendbuff.toLocal8Bit().data(),sendbuff.length(),address,port);:将sendbuff转换为本地8位编码(通常是ISO8859-1或Windows-1252),然后使用QUdpSocket的writeDatagram方法发送数据报到指定的地址和端口。

第三步:运行程序,并验证发送数据功能

4. 关闭UDP

第一步:关联“关闭按钮控件”信号和槽(自动关联);

第二步:编写代码,关闭UDP;

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号