UDP
UDP(User Datagram Protocol,用户数据报协议)是一个轻量级的、不提供可靠性保证的、面向数据报的无连接协议,用于可靠性不是非常重要的情况。例如,传感器数据传输:一些传感器数据,如温度、湿度等环境监测数据,可能需要实时传输,但对于丢失一些数据并不是很敏感。UDP 能够提供更低的延迟,因为他没有 TCP 那样的握手和连接管理过程。
UDP 一般分为发送端和接收端,如图所示:
QUdpSocket 类用来发送和接收 UDP 数据报,继承自 QAbstractSocket。这里的 Socket 就是所谓的"套接字",简单来说,套接字就是一个 IP 地址加一个 port 端口号。其中,IP 地址指定了网络中的一台主机,而端口号指定了该主机上的一个网络程序,这样使用套接字就可以实现网络上两台主机的两个应用程序之间的通信。
发送端
widget.h
C++
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected slots:
//! 发送数据报
void on_btnSendMsg_clicked();
private:
Ui::Widget *ui;
QUdpSocket *m_udpSocket{};
};
#endif // WIDGET_H
widget.cpp
C++
#include "widget.h"
#include "./ui_widget.h"
#include <QUdpSocket>
#include <QNetworkDatagram>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
m_udpSocket = new QUdpSocket(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnSendMsg_clicked()
{
QString msg = ui->textEdit->toPlainText();
m_udpSocket->writeDatagram(msg.toLocal8Bit(), QHostAddress("192.168.0.202"), 1234);
}
发送界面展示:
接收端
widget.h
C++
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
//! 处理挂起数据报
void processPendingDatagram();
private:
Ui::Widget *ui;
QUdpSocket *m_udpSocket{};
};
#endif // WIDGET_H
widget.cpp
C++
#include "widget.h"
#include "./ui_widget.h"
#include <QUdpSocket>
#include <QNetworkDatagram>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
m_udpSocket = new QUdpSocket(this);
bool ret = m_udpSocket->bind(QHostAddress::Any, 1234);
if (!ret) {
qDebug() << "udp bind failed !";
}
connect(m_udpSocket, &QUdpSocket::readyRead, this, &Widget::processPendingDatagram);
}
Widget::~Widget()
{
delete ui;
}
void Widget::processPendingDatagram()
{
if (!m_udpSocket->hasPendingDatagrams()
|| m_udpSocket->pendingDatagramSize() <= 0) {
return;
}
while (m_udpSocket->hasPendingDatagrams()) {
ui->textEdit->insertPlainText(m_udpSocket->receiveDatagram().data());
}
}
接收界面展示:
总结
QUdpSocket以数据报传输数据,而不是连续的数据流。由于少了连接,客户端与服务端没有太大区别,所以可以看作只有发送端和接收端。无论是发送端还是接收端,都只有一个套接字,也就是 QUdpSocket。此外,UDP 通信中没有监听 listen(),只有绑定 bind(),往套接字中读写数据用 readDataGram()和writeDataGram()(不能超过512字节)。