Qt:UDP

1:UDP通信概述

UDP(User Datagram Protocol,用户数据报协议)是轻量的,不可靠的,面向数据报,无连接的协议。两个UDP之间通信无需建立持久的连接,每次发送数据都需要指定目标地址和端口。
UDP分为单播,广播,组播三种模式。在单播,广播,组播的模式下,UDP程序都是对等的。

1.1 单播

一个UDP客户端发送的数据报只能发送到另一个指定的地址和端口的UDP客户端,是一对一数据的传输。

1.2 广播

一个UDP客户端发出的数据报,在同一网络范围内其他所有的UDP客户端都可以收到,QUdpSocket支持IPV4广播。要获取广播数据只需要在数据报中接收端地址为QHostAddress::Broadcast,一般的广播地址是:255.255.255.255

1.3 组播

组播也称为多播,UDP客户端加入到另一个组播IP地址指定的多播组,成员向组播地址发送的数据报组内成员都可以接收到,类似于QQ群。QUdpSocket::joinMulticastGroup()函数实现加入多播组功能,加入多播组后,UDP数据的手法和正常的都一样。关于组播的ip地址,有以下约定

  • 244.0.0.0 - 244.0.0.255为预留的组播地址(永久组地址),地址244.0.0.0保留不进行分配,其他地址路由协议使用。
  • 224.0.1.0 - 224.0.1.255 是公用组播地址,可以用于Internet。
  • 224.0.2.0 - 238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效。
  • 239.0.0.0 - 239.255.255.255 为本地管理的组播地址,在特定的本地范围内可用。

因此本次测试使用的地址范围是:239.0.0.0 - 239.255.255.255 leaveMulticastGroup()使得一个主机离开多播组,oinMulticastGroup()函数实现加入多播组功能。

2 单播和广播例子

页面设计如下:
请添加图片描述

#pragma once

#include <QtWidgets/QWidget>
#include <QtNetwork>
#include <QDebug>
#include <QHostInfo>
#include <QAbstractSocket>
#include <QUdpSocket>
#include <QByteArray>
#include "ui_QtWidgetsApplicationUDP.h"

class QtWidgetsApplicationUDP : public QWidget
{
    Q_OBJECT

public:
    QtWidgetsApplicationUDP(QWidget *parent = Q_NULLPTR);

private:
    Ui::QtWidgetsApplicationUDPClass ui;
    QUdpSocket* m_udpSocket = nullptr;

private:
    QString getLocalIP();

private slots:
    void onSocketStateChanged(QAbstractSocket::SocketState socketState);
    void onSocketReadyRead();
    void on_clearText_clicked();
    void on_exit_clicked();
    void on_actStart_clicked();
    void on_actStop_clicked();
    void on_btnSend_clicked();
    void on_btnBroadcast_clicked();
};

#include "QtWidgetsApplicationUDP.h"

QtWidgetsApplicationUDP::QtWidgetsApplicationUDP(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    QString _loaclIP = getLocalIP();
    this->setWindowTitle(this->windowTitle() + u8"本机IP:" + _loaclIP);
    ui.lineEdit->setText(_loaclIP);

    m_udpSocket = new QUdpSocket(this);
    onSocketStateChanged(m_udpSocket->state());
    connect(m_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
    connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));
}

QString QtWidgetsApplicationUDP::getLocalIP()
{
    QString _hostName = QHostInfo::localHostName();// 本地主机名称
    QHostInfo _hostInfo = QHostInfo::fromName(_hostName);
    QString _loacalIP = "";
    QList<QHostAddress> _address = _hostInfo.addresses();
    if (!_address.isEmpty())
    {
        for (int i = 0; i < _address.count(); i++)
        {
            QHostAddress _aHost = _address.at(i);
            if (QAbstractSocket::IPv4Protocol == _aHost.protocol())
            {
                _loacalIP = _aHost.toString();
                break;
            }
        }
    }
    qDebug() << _loacalIP;
    return _loacalIP;
}

void QtWidgetsApplicationUDP::onSocketStateChanged(QAbstractSocket::SocketState socketState)
{
    switch (socketState)
    {

    case QAbstractSocket::UnconnectedState:
        ui.label_4->setText("UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        ui.label_4->setText("HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        ui.label_4->setText("ConnectingState");
        break;
    case QAbstractSocket::ConnectedState:
        ui.label_4->setText("ConnectedState");
        break;
    case QAbstractSocket::BoundState:
        ui.label_4->setText("BoundState");
        break;
    case QAbstractSocket::ListeningState:
        ui.label_4->setText("ListeningState");
        break;
    case QAbstractSocket::ClosingState:
        ui.label_4->setText("ClosingState");
        break;
    default:
        break;
    }
}

void QtWidgetsApplicationUDP::onSocketReadyRead()
{
    while (m_udpSocket->hasPendingDatagrams())
    {
        QByteArray _datagram;
        _datagram.resize(m_udpSocket->pendingDatagramSize());
        QHostAddress _peerAddr;
        quint16 _peerPort;
        m_udpSocket->readDatagram(_datagram.data(), _datagram.size(), &_peerAddr, &_peerPort);
        QString _str = _datagram.data();
        QString _peer = "[From " + _peerAddr.toString() + ":" + QString::number(_peerPort) + "] ";
        ui.plainTextEdit->appendPlainText(_peer + _str);
    }
}

void QtWidgetsApplicationUDP::on_clearText_clicked()
{
    ui.plainTextEdit->clear();
}

void QtWidgetsApplicationUDP::on_exit_clicked()
{
    exit(0);
}

void QtWidgetsApplicationUDP::on_actStart_clicked()
{
    quint16 _port = ui.spinBox->value();
    if (m_udpSocket->bind(_port))
    {
        ui.plainTextEdit->appendPlainText(u8"成功绑定" + QString::number(m_udpSocket->localPort()));
        ui.actStart->setEnabled(false);
        ui.actStop->setEnabled(true);
    }
    else
    {
        ui.plainTextEdit->appendPlainText(u8"绑定失败");
    }
}

void QtWidgetsApplicationUDP::on_actStop_clicked()
{
    m_udpSocket->abort();
    ui.actStart->setEnabled(true);
    ui.actStop->setEnabled(false);
    ui.plainTextEdit->appendPlainText(u8"已解除绑定");
}

void QtWidgetsApplicationUDP::on_btnSend_clicked()
{
    QString _targetIP = ui.lineEdit->text();
    QHostAddress _targetdress(_targetIP);
    quint16 _targetPort = ui.spinBox_2->value();
    QString _msg = ui.lineEdit_2->text();
    QByteArray _str = _msg.toUtf8();
    m_udpSocket->writeDatagram(_str, _targetdress, _targetPort);
    ui.plainTextEdit->appendPlainText("[OUT] " + _msg);
    ui.lineEdit_2->clear();
    ui.lineEdit_2->setFocus();
}

void QtWidgetsApplicationUDP::on_btnBroadcast_clicked()
{
    quint16 _targetPort = ui.spinBox_2->value();
	QString _msg = ui.lineEdit_2->text();
	QByteArray _str = _msg.toUtf8();
    m_udpSocket->writeDatagram(_str, QHostAddress::Broadcast, _targetPort);
    ui.plainTextEdit->appendPlainText("[OUT] " + _msg);
	ui.lineEdit_2->clear();
	ui.lineEdit_2->setFocus();
}

操作视频:

请添加图片描述

3 组播例子

#pragma once

#include <QtWidgets/QWidget>
#include <QtNetwork>
#include <QDebug>
#include <QHostInfo>
#include <QAbstractSocket>
#include <QUdpSocket>
#include <QByteArray>
#include "ui_QtWidgetsApplicationUDPZB.h"

class QtWidgetsApplicationUDPZB : public QWidget
{
    Q_OBJECT

public:
    QtWidgetsApplicationUDPZB(QWidget *parent = Q_NULLPTR);
    QUdpSocket* m_udpSocket = nullptr;
    QHostAddress groupAdress;//组播地址
    QString getLocalIP();

private:
    Ui::QtWidgetsApplicationUDPZBClass ui;

private slots:
	void onSocketStateChanged(QAbstractSocket::SocketState socketState);
	void onSocketReadyRead();
	void on_clearText_clicked();
	void on_exit_clicked();
	void on_actStart_clicked();
	void on_actStop_clicked();
	void on_btnSend_clicked();
};

#include "QtWidgetsApplicationUDPZB.h"

QtWidgetsApplicationUDPZB::QtWidgetsApplicationUDPZB(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
	QString _loaclIP = getLocalIP();
	this->setWindowTitle(this->windowTitle() + u8"本机IP:" + _loaclIP);

	m_udpSocket = new QUdpSocket(this);
	m_udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1);
	onSocketStateChanged(m_udpSocket->state());
	connect(m_udpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
	connect(m_udpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));
}

QString QtWidgetsApplicationUDPZB::getLocalIP()
{
	QString _hostName = QHostInfo::localHostName();// 本地主机名称
	QHostInfo _hostInfo = QHostInfo::fromName(_hostName);
	QString _loacalIP = "";
	QList<QHostAddress> _address = _hostInfo.addresses();
	if (!_address.isEmpty())
	{
		for (int i = 0; i < _address.count(); i++)
		{
			QHostAddress _aHost = _address.at(i);
			if (QAbstractSocket::IPv4Protocol == _aHost.protocol())
			{
				_loacalIP = _aHost.toString();
				break;
			}
		}
	}
	qDebug() << _loacalIP;
	return _loacalIP;
}

void QtWidgetsApplicationUDPZB::onSocketStateChanged(QAbstractSocket::SocketState socketState)
{
	switch (socketState)
	{

	case QAbstractSocket::UnconnectedState:
		ui.label_4->setText("UnconnectedState");
		break;
	case QAbstractSocket::HostLookupState:
		ui.label_4->setText("HostLookupState");
		break;
	case QAbstractSocket::ConnectingState:
		ui.label_4->setText("ConnectingState");
		break;
	case QAbstractSocket::ConnectedState:
		ui.label_4->setText("ConnectedState");
		break;
	case QAbstractSocket::BoundState:
		ui.label_4->setText("BoundState");
		break;
	case QAbstractSocket::ListeningState:
		ui.label_4->setText("ListeningState");
		break;
	case QAbstractSocket::ClosingState:
		ui.label_4->setText("ClosingState");
		break;
	default:
		break;
	}
}

void QtWidgetsApplicationUDPZB::onSocketReadyRead()
{
	while (m_udpSocket->hasPendingDatagrams())
	{
		QByteArray _datagram;
		_datagram.resize(m_udpSocket->pendingDatagramSize());
		QHostAddress _peerAddr;
		quint16 _peerPort;
		m_udpSocket->readDatagram(_datagram.data(), _datagram.size(), &_peerAddr, &_peerPort);
		QString _str = _datagram.data();
		QString _peer = "[From " + _peerAddr.toString() + ":" + QString::number(_peerPort) + "] ";
		ui.plainTextEdit->appendPlainText(_peer + _str);
	}
}

void QtWidgetsApplicationUDPZB::on_clearText_clicked()
{
	ui.plainTextEdit->clear();
}

void QtWidgetsApplicationUDPZB::on_exit_clicked()
{
	exit(0);
}

void QtWidgetsApplicationUDPZB::on_actStart_clicked()
{
	QString ip = ui.lineEdit->text();
	groupAdress = QHostAddress(ip);
	quint16 groupPort = ui.spinBox->value();
	if (m_udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress))
	{
		m_udpSocket->joinMulticastGroup(groupAdress);
		ui.plainTextEdit->appendPlainText(u8"加入多播组");
		ui.actStart->setEnabled(false);
		ui.actStop->setEnabled(true);

	}
	else
	{
		ui.plainTextEdit->appendPlainText(u8"加入多播组失败");
	}
}

void QtWidgetsApplicationUDPZB::on_actStop_clicked()
{
	m_udpSocket->leaveMulticastGroup(groupAdress);
	m_udpSocket->abort();
	ui.actStart->setEnabled(true);
	ui.actStop->setEnabled(false);
	ui.plainTextEdit->appendPlainText(u8"已解除绑定");
}

void QtWidgetsApplicationUDPZB::on_btnSend_clicked()
{

	quint16 _targetPort = ui.spinBox->value();
	QString _msg = ui.lineEdit_2->text();
	QByteArray _str = _msg.toUtf8();
	m_udpSocket->writeDatagram(_str, groupAdress, _targetPort);
	ui.plainTextEdit->appendPlainText("[OUT] " + _msg);
	ui.lineEdit_2->clear();
	ui.lineEdit_2->setFocus();
}

m_udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1);设置缺省值为1,指的是UDP组播的数据报生存周期,跨过一个路由器,就会减去1,默认值为1,则代表只在同一个路由器下的局域网传播。

m_udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress)绑定的地址为QHostAddress::AnyIPv4,端口是多播组统一端口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值