Qt学习笔记之UDP通信
Qt学习笔记之UDP通信
本文将详细介绍如何使用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步:
- 接收框:Plain Text Edit控件(重命名:receiveEdit)
- 发送框:Line Edit控件(重命名:sendEdit)
- 接收窗口和发送窗口:Group Box控件
- 本地端口框:Line Edit(重命名:localPort) + Label控件
- 目标端口框:Line Edit(重命名:aimPort) + Label控件
- 目标IP框:Line Edit(重命名:aimIp) + Label控件
- 按钮:PushButton 控件:
打开(重命名:openBt)、关闭(重命名:closeBt)、发送(重命名:sendBt)
最后设置编译运行效果如下:
四、新类的使用(QUdpSocket Class)
步骤:帮助->索引->搜索“QUdpSocket类”
下滑可查看使用示例:
- 在widget.h文件中,添加所用头文件:#include
- 在.pro文件中,添加network;
- 在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中设计的用户界面的所有部件。
- ui->localPort:这通常是一个指向QLineEdit或类似文本输入控件的指针,它允许用户输入数据。
- ->text():这是对QLineEdit或文本输入控件的成员函数调用,用于获取用户输入的文本。
- .toUInt():这是一个将QString对象(用户输入的文本)转换为unsignedint(无符号整数)的方法。这里使用toUInt()是因为它期望端口号是一个非负整数,而端口号的范围是从0到65535。
- 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数据报的逻辑:
- address.setAddress(ui->aimIp->text());:获取用户在UI组件中输入的目标IP地址,并将该地址设置为QHostAddress对象。
- sendbuff=ui->sendEdit->text();:获取用户在发送文本编辑器中输入的字符串,这将作为UDP数据报的内容。
- port=ui->aimPort->text().toUInt();:获取用户输入的目标端口号,并转换为无符号整数。
4.udpSocket->writeDatagram(sendbuff.toLocal8Bit().data(),sendbuff.length(),address,port);:将sendbuff转换为本地8位编码(通常是ISO8859-1或Windows-1252),然后使用QUdpSocket的writeDatagram方法发送数据报到指定的地址和端口。