10.4 基于UDP的广播程序
10.4 基于UDP的广播程序
UDP(User Data Protocol)是一种基于数据报的传输层的协议,它是一种面向无连接,且不负责数据可靠性的网络传输层协议。它常常被用在一些对速度要求比较快的场合中,比如直播,短消息等场合中。它适用于以下的场景:
(1)拥有大量客户端
(2)对速度要求高
(3)传送的内容可以忍受信息的丢失
(4)面向无连接
10.4.1 UDP协议的工作原理
UDP的首先要知道它不需要面向连接,在最简单的双向通信的例子中,客户端和服务器端之间只需要有各自所绑定的端口即可,而IP地址只要是位于同一子网就行。而UDP协议本身也规定了最大的报文大小一般是64kb。由于UDP协议不存在超时重传机制,因此服务器端未收到请求时,客户端不会进行重发。因此报文的传输是不可靠的。客户端和服务端遵循着:请求-应答-请求-应答-请求应答-....这样的流程来完成数据的传输。
10.4.2 UDP编程模型
对于UDP的编程模型,具体分为了客户端和服务端两个部分。那么服务端的话,一般的步骤是:初始化套接字->绑定服务端的端口号->接收数据。而客户端的话,就是:初始化套接字->绑定端口(可有可无)->发送数据到服务端对应的端口上。
10.4.3 UDP服务器的编程实例
案例(一)编写一个简单的UDP服务端的广播程序
(1)新建QT GUI应用程序,类名为UDPServer,基类选择QWidget。
(2)在udpserver.h中编写以下成员
#ifndef UDPSERVER_H
#define UDPSERVER_H
#include <QList>
#include <QLabel>
#include <QDebug>
#include <QTimer>
#include <QWidget>
#include <QLineEdit>
#include <QMessageBox>
#include <QUdpSocket>
#include <QPushButton>
#include <QVBoxLayout>
class UDPServer : public QWidget
{
Q_OBJECT
public:
UDPServer(QWidget *parent = nullptr);
~UDPServer();
private slots:
void onTimeOut();
void onClicked();
private:
QLabel*m_timerLabel;
QLineEdit*m_timeLineEdit;
QPushButton*m_startPushButton;
private:
QUdpSocket*m_serverSocket;
private:
QVBoxLayout*m_mainLayout;
private:
QTimer*m_timer;
};
#endif // UDPSERVER_H
(3)在udpserver.cpp中添加这些实现
#include "udpserver.h"
UDPServer::UDPServer(QWidget *parent):QWidget(parent)
{
m_mainLayout = new QVBoxLayout(this);
m_timerLabel = new QLabel("计时器:");
m_timeLineEdit = new QLineEdit;
m_startPushButton = new QPushButton("开始");
m_timer = new QTimer(this);
m_mainLayout->addWidget(m_timerLabel);
m_mainLayout->addWidget(m_timeLineEdit);
m_mainLayout->addWidget(m_startPushButton);
m_serverSocket = new QUdpSocket(this);
m_serverSocket->bind(8888);//我们为Server绑定一个端口
connect(this->m_startPushButton,&QPushButton::clicked,this,&UDPServer::onClicked);
connect(this->m_timer,&QTimer::timeout,this,&UDPServer::onTimeOut);
}
UDPServer::~UDPServer()
{
delete m_timerLabel;
m_timerLabel = nullptr;
delete m_timeLineEdit;
m_timeLineEdit = nullptr;
delete m_startPushButton;
m_startPushButton = nullptr;
delete m_mainLayout;
m_mainLayout = nullptr;
delete m_serverSocket;
m_serverSocket = nullptr;
delete m_timer;
m_timer = nullptr;
}
void UDPServer::onTimeOut()
{
char data[] = "Hello,World!\n";
this->m_serverSocket->writeDatagram(data,sizeof(data),QHostAddress(QHostAddress::Broadcast),9999);//我们知道Client的端口是9999,那么直接发送即可
}
void UDPServer::onClicked()
{
if(this->m_timeLineEdit->text().isEmpty())
{
QMessageBox::warning(this,QString("提示"),QString("未输入任何的时长!"));
}
else
{
if(m_startPushButton->text() == "开始")
{
bool isOk(false);
int ms = this->m_timeLineEdit->text().toInt(&isOk);
if(!isOk)
{
QMessageBox::warning(this,QString("提示"),QString("输入的信息不合法!"));
}
else
{
m_timer->start(ms);
m_startPushButton->setText("停止");
m_timeLineEdit->setReadOnly(true);
}
}
else
{
m_timer->stop();
m_startPushButton->setText("开始");
m_timeLineEdit->setReadOnly(false);
}
}
}
(4)客户端的编写
新建QT GUI程序,类名为UDPClient,基类为QWidget,不需要创建UI文件
(5)在udpclient.h中写以下成员
#ifndef UDPCLIENT_H
#define UDPCLIENT_H
#include <QWidget>
#include <QUdpSocket>
#include <QLineEdit>
#include <QLabel>
#include <QHostAddress>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
class UDPClient : public QWidget
{
Q_OBJECT
public:
UDPClient(QWidget *parent = nullptr);
~UDPClient();
private slots:
void onReadyRead();
void onClose();
private:
QTextEdit*m_textEdit;
QPushButton*m_closePushButton;
QVBoxLayout*m_mainLayout;
private:
QUdpSocket*m_clientSocket;
};
#endif // UDPCLIENT_H
(6)在udpclient.cpp中进行实现
#include "udpclient.h"
UDPClient::UDPClient(QWidget *parent)
: QWidget(parent)
{
m_mainLayout = new QVBoxLayout(this);
m_textEdit = new QTextEdit;
m_textEdit->setReadOnly(true);
m_closePushButton = new QPushButton("关闭");
m_clientSocket = new QUdpSocket(this);
m_mainLayout->addWidget(m_textEdit);
m_mainLayout->addWidget(m_closePushButton);
m_clientSocket->bind(9999);//为客户端也绑定一个端口
connect(this->m_clientSocket,&QUdpSocket::readyRead,this,&UDPClient::onReadyRead);
connect(this->m_closePushButton,&QPushButton::clicked,this,&UDPClient::onClose);
}
UDPClient::~UDPClient()
{
delete m_textEdit;
m_textEdit = nullptr;
delete m_closePushButton;
m_closePushButton = nullptr;
delete m_mainLayout;
m_mainLayout = nullptr;
delete m_clientSocket;
m_clientSocket = nullptr;
}
void UDPClient::onReadyRead()
{
while(m_clientSocket->hasPendingDatagrams())
{
char data[1024] = {0};
QHostAddress serverHost;
quint16 serverPort;
m_clientSocket->readDatagram(data,sizeof (data),&serverHost,&serverPort);
m_textEdit->insertPlainText(QString("%1(%2)%3").arg(serverHost.toString()).arg(serverPort).arg(data));
}
}
void UDPClient::onClose()
{
this->close();
}
(7)运行

本节代码:https://files.cnblogs.com/files/blogs/792763/UDP.zip?t=1720537969&download=true

浙公网安备 33010602011771号