欢迎小伙伴的点评✨✨,相互学习c/c++应用开发。🍳🍳🍳
博主🧑🧑 本着开源的精神交流Qt开发的经验、将持续更新续章,为社区贡献博主自身的开源精神👩🚀
目录
前言
本章节会给大家带来Qt5 网络与通信—— 基于 UDP 的网络广播程序实例详解。
一、基于 TCP 的网络聊天室程序概述
用户数据报协议 (User Data Protocol, UDP) 是一种简单轻量级、不可靠、面向数据报、无连接的传输层协议,可以应用在可靠性不是十分重要的场合,如短消息、广播信息等。
适合应用的情况有以下几种:
- 网络数据大多为短消息。
- 拥有大量客户端。
- 对数据安全性无特殊要求。
- 网络负担非常重,但对响应速度要求高。
1.1、UDP工作原理
如下图所示,UDP 客户端向 UDP 服务器发送一定长度的请求报文,报文大小的限制与各系统的协议实现有关,但不得超过其下层 IP 规定的 64KB; UDP 服务器同样以报文形式做出响应。如果服务器未收到此请求,客户端不会进行重发,因此报文的传输是不可靠的。
例如,常用的聊天工具一腾讯 QQ 软件就是使用 UDP 发送消息的,因此有时会出现收不
到消息的情况。
1.2、UDP 编程模型
下面介绍基于UDP 的经典编程模型, UDP 客户端与服务器间的交互时序如下图所示 。
可以看出,在 UDP 方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发出数据报。类似地,服务器也不从客户端接收连接,只负责调用接收函数,等待来自某客户端的数据到达。
Qt 中通过 QUdpSocket 类实现 UDP 协议的编程。下面通过一个实例,介绍如何实现基于
UDP 的广播应用,它由 UDP 服务器和 UDP 客户端两部分组成。
二、效果实例
图一
三、原码解析
3.1首先先在新建好的工程文件xxx.pro文件中加入
QT += network
udpclient.h
#ifndef UDPCLIENT_H
#define UDPCLIENT_H
#include <QDialog>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QPushButton>
#include <QUdpSocket>
class UdpClient : public QDialog
{
Q_OBJECT
public:
UdpClient(QWidget *parent= 0,Qt::WindowFlags f=0);
~UdpClient () ;
private:
QTextEdit *ReceiveTextEdit;
QPushButton *CloseBtn;
QVBoxLayout *mainLayout;
public slots:
void CloseBtnClicked();
void dataReceived();
private:
int port;
QUdpSocket *udpSocket;
};
#endif // UDPCLIENT_H
udpserver.h
#ifndef UDPSERVER_H
#define UDPSERVER_H
#include <QDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>
#include <QUdpSocket>
#include <QTimer>
class UdpServer : public QDialog
{
Q_OBJECT
public:
explicit UdpServer(QWidget *parent = 0,Qt::WindowFlags f=0);
~UdpServer();
private:
QLabel *TimerLabel;
QLineEdit *TextLineEdit;
QPushButton *StartBtn;
QVBoxLayout *mainLayout;
public slots:
void StartBtnClicked();
void timeout();
private:
int port;
bool isStarted;
QUdpSocket *udpSocket;
QTimer *timer;
};
#endif // UDPSERVER_H
main.cpp
#include "udpserver.h"
#include "udpclient.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
UdpServer wS;
UdpClient wC;
wS.show();
wC.show();
return a.exec();
}
udpclient.cpp
#include "udpclient.h"
#include <QMessageBox>
#include <QHostAddress>
UdpClient::UdpClient (QWidget *parent, Qt::WindowFlags f)
: QDialog(parent,f)
{
setWindowTitle(tr("UDP Client")) ; //设置窗体的标题
/*初始化各个控件*/
ReceiveTextEdit = new QTextEdit(this);
CloseBtn = new QPushButton(tr("Close"),this);
/*设置布局*/
mainLayout =new QVBoxLayout(this);
mainLayout->addWidget(ReceiveTextEdit);
mainLayout->addWidget(CloseBtn);
connect(CloseBtn, SIGNAL (clicked()), this, SLOT (CloseBtnClicked ()));
port =5555; //设置 UDP 的端口号参数,指定在此端口上监听数据
udpSocket = new QUdpSocket(this); //创建一个 QUdpSocket
connect (udpSocket, SIGNAL (readyRead ()), this, SLOT (dataReceived ()));
/*连接 QIODevice
的 readyRead()信号。 QUdpSocket 也是一个 I/O 设备,从 QIODevice 继承而来,当有数据到达 I/O
设备时,发出 readyRead()信号。*/
bool result=udpSocket->bind(port); //绑定到指定的端口上
if (!result)
{
QMessageBox::information(this,tr("error"),tr("udp socket create error!")) ;
return;
}
}
void UdpClient::CloseBtnClicked()
{
close();
}
/*dataReceived() 函数响应 QUdpSocket 的 readyRead()信号,一旦 UdpSocket 对象中有数据可
读时,即通过 readDatagram()方法将数据读出并显示。*/
void UdpClient::dataReceived ()
{
while (udpSocket->hasPendingDatagrams()) //(a)
{
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize()); /*判断 UdpSocket 中是否有数据报可读,
hasPendingDatagramsO方法在至少有一个数据报可读时返回 true, 否则返回 false 。*/
udpSocket->readDatagram(datagram.data(),datagram.size());
QString msg=datagram.data(); /*实现了读取第一个数据报, pendingDatagramSize()可以获得第一个数据报的长度。
同时运行 UdpServer 与 UdpClient 工程,首先在服务器界面的文本框中输入 "hello !", 然后
单击“开始”按钮,按钮文本变为“停止",客户端就开始不断地收到 "hello!" 字符消息并显
示在文本区,当单击服务器的“停止”按钮后,按钮文本又变回“开始”,客户端也就停止了字
符的显示,再次单击服务器的“开始”按钮,客户端又继续接收并显示……如此循环往复*/
ReceiveTextEdit->insertPlainText(msg); //显示数据
}
}
UdpClient::~UdpClient()
{
}
udpserver.cpp
#include "udpserver.h"
#include <QHostAddress>
#include <QDebug>
UdpServer::UdpServer(QWidget *parent,Qt::WindowFlags f):QDialog(parent,f)
{
setWindowTitle(tr("UDP Server"));
/*尸初始化各个控件*/
TimerLabel = new QLabel(tr(" 计时器: "),this);
TextLineEdit = new QLineEdit(this);
StartBtn = new QPushButton(tr(" 开始"),this);
/*设置布局*/
mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(TimerLabel);
mainLayout->addWidget(TextLineEdit);
mainLayout->addWidget(StartBtn);
connect (StartBtn, SIGNAL (clicked()), this, SLOT (StartBtnClicked())) ;
port=5555; //设置 UDP 的端口号参数,服务器定时向此端口发送广播信息
isStarted = false;
udpSocket = new QUdpSocket(this);
timer= new QTimer(this); //创建一个 QUdpSocket
//定时发送广播信息
connect (timer, SIGNAL (timeout()), this, SLOT(timeout())); //每隔1秒调用一次
}
UdpServer::~UdpServer()
{
}
/*使用延时每隔1秒触发一次timeout*/
void UdpServer::StartBtnClicked()
{
if(!isStarted)
{
StartBtn->setText(tr(" 停止")) ;
timer->start(1000); //每隔1秒发送一次
isStarted =true;
}
else
{
StartBtn->setText(tr(" 开始")) ;
isStarted = false;
timer->stop();
}
}
/*timeout() 函数完成了向端口发送广播信息的功能,*/
void UdpServer::timeout ()
{
QString msg = TextLineEdit->text ();
int length=0;
if(msg=="")
{
return;
}
if((length=udpSocket->writeDatagram(msg.toLatin1(),msg.length() ,QHostAddress::Broadcast,port)) !=msg.length())
{
return;
}
}
四、总结
Qt5 网络与通信—— 基于 UDP 的网络广播程序会在应用程序开发中经常用到的。