组播是主机之间“一对一组”的通信模式,当多个客户端加入由一个组播地址定义的多播组之后,客户端向组播地址和端口发送数据报,组内成员都可以接收到,类似QQ群。
UDP组播必须使用一个组播地址。组播地址是D类IP地址,有特定的地址段。多播组可以是永久的也可以是临时的。永久多播组保持不变的是它的IP地址,组内成员结构可以发生变化。
224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.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为本地管理组播地址,仅在特定的本地范围内有效
若在家庭或办公室局域网内测试UDP组播功能,可以使用组播地址范围是239.0.0.0~239.255.255.255
joinMulticastGroup()函数使主机加入一个多播组,leaveMulticastGroup()函数使主机离开一个多播组。
UDP组播的特点是使用组播地址,其他的端口绑定、数据报收发功能与单播UDP完全相同。
实现代码如下:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QUdpSocket>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_btnClear_clicked();
void on_btnSend_clicked();
void on_readyRead();
void on_btnJoin_clicked();
void on_btnExit_clicked();
private:
Ui::Widget *ui;
private:
QUdpSocket *m_udpSocket = nullptr;
QHostAddress groupAddr; //组播地址
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QHostInfo>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//本地主机名
QString hostName = QHostInfo::localHostName();
m_udpSocket = new QUdpSocket(this);
//socket QAbstractSocket::MulticastTtlOption值为1,MulticastTtlOption是
//组播的数据的生存期,数据报没跨1个路由就会减1.表示多播数据报只能在同一路由下的局域网内传播
m_udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
connect(m_udpSocket,&QUdpSocket::readyRead,this,&Widget::on_readyRead);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_btnClear_clicked()
{
ui->plainTextEdit->clear();
}
void Widget::on_btnSend_clicked()//组播
{
//目标端口
quint16 groupPort = ui->spinBindPort->value();
QString msg = ui->lineEdit->text();
QByteArray str = msg.toUtf8();
//发出数据报
m_udpSocket->writeDatagram(str,groupAddr,groupPort);
ui->plainTextEdit->appendPlainText("[multicast] "+msg);
}
void Widget::on_readyRead()
{
while(m_udpSocket->hasPendingDatagrams())
{
QByteArray data;
data.resize(m_udpSocket->pendingDatagramSize());
QHostAddress peerAddr;
quint16 peerPort;
m_udpSocket->readDatagram(data.data(),data.size(),&peerAddr,&peerPort);
QString str = data.data();
QString peer = "[From ] +"+peerAddr.toString()+":"+QString::number(peerPort)+"] ";
ui->plainTextEdit->appendPlainText(peer+str);
}
}
void Widget::on_btnJoin_clicked()
{
QString IP = ui->comboBox->currentText();
groupAddr = QHostAddress(IP);
quint16 groupPort = ui->spinBindPort->value();
//加入组播之前,必须先绑定端口,端口为多播组统一的一个端口。
if(m_udpSocket->bind(QHostAddress::AnyIPv4,groupPort,QUdpSocket::ShareAddress))
{
//加入组播
m_udpSocket->joinMulticastGroup(groupAddr);
ui->plainTextEdit->appendPlainText("**加入组播成功");
ui->plainTextEdit->appendPlainText("**组播IP: "+ IP);
ui->plainTextEdit->appendPlainText("**绑定端口: "+QString::number(groupPort));
ui->btnJoin->setEnabled(false);
ui->btnExit->setEnabled(true);
ui->comboBox->setEnabled(false);
}
else
{
ui->plainTextEdit->appendPlainText("**绑定端口失败");
}
}
void Widget::on_btnExit_clicked()
{
//退出组播
m_udpSocket->leaveMulticastGroup(groupAddr);
//解除绑定
m_udpSocket->abort();
ui->btnJoin->setEnabled(true);
ui->btnExit->setEnabled(false);
ui->comboBox->setEnabled(true);
ui->plainTextEdit->appendPlainText("**已退出组播");
}
原文链接:https://blog.youkuaiyun.com/wzz953200463/article/details/115101133