一、UDP通信
使用Qt来实现TCP和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 示例:
1. QTcpSocket *socket = new QTcpSocket(this);
2. socket->connectToHost("server.example.com", 1234);
3. connect(socket, &QTcpSocket::readyRead, this, &MyClass::onReadyRead);
4. socket->write("Hello, Server!");
② UDP 示例:
1. QUdpSocket *socket = new QUdpSocket(this);
2. socket->bind(QHostAddress::Any, 1234);
3. connect(socket, &QUdpSocket::readyRead, this, &MyClass::onReadyRead);
4. 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 <QUdpSocket>
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 对象(用户输入的文本)转换为 unsigned int(无符号整数)的方法。这里使用 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. QByteArray array; 创建一个 QByteArray 对象用于存储接收到的数据。
3. array.resize(udpSocket->pendingDatagramSize()); 调整 QByteArray 的大小以匹配即将读取的数据报的大小。
4. udpSocket->readDatagram(array.data(), array.size()); 从 QUdpSocket 读取一个数据报到 QByteArray。
5. QString buff; 创建一个 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位编码(通常是ISO 8859-1或Windows-1252),然后使用 QUdpSocket 的 writeDatagram 方法发送数据报到指定的地址和端口。
第三步:运行程序,并验证发送数据功能
4. 关闭UDP
第一步:关联“关闭按钮控件”信号和槽(自动关联);
第二步:编写代码,关闭UDP;
【笔记学习自北京讯为电子嵌入式学习之QT学习篇】