Qt网络-UDP组播(三)

1. UDP组播特性

UDP组播是主机之间 " 一对一组 " 的通信模式,
当多个客户端加入由一个组播地址定义的多播组之后,
客户端向组播地址和端口发送的UDP数据报,组内成员都可以接收到。

用同一个IP多播地址接收多播数据报的所有主机构成了一个组,称为多播组(或组播组)。
所有的信息接收者都加入到一个组内,加入之后,流向组地址的数据报开始向接收者传输,
组中的所有成员都能接收到数据报。组中的成员是动态的,主机可以在任何时间加入和离开组。

采用UDP组播必须使用一个组播地址。组播地址(组播报文的目的地址)
是D类IP地址(D类地址不能出现在IP报文的源IP地址字段),有特定的地址段。
多播组可以是永久的也可以是临时的。多播组地址中,有一部分由官方分配,称为永久多播组。
永久多播组保持并联的是它的IP地址,组中的成员构成可以发生变化。
永久多播组中的成员数量可以是任意的,可以为零。
那些没有保留下来的供永久多播组使用的IP组播地址,可以被临时多播组使用。

2. 组播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:为用户可用的组播地址(临时组地址),全网范围内有效;
 - 239.0.0.0~239.255.255.255:为本地 管理组播地址,仅在特定的本地范围内有效。
 在家庭或办公室局域网内测试UDP组播功能,可以使用的组播地址范围是239.0.0.0~239.255.255.255。

3. Qt程序实现

(1)声明所需变量:

    QUdpSocket *udpSocket; //用于与连接的客户端通讯的QUdpSocket
    QHostAddress groupAddress; //组播地址

(2)声明槽函数:

// 自定义槽函数
void onSocketReadyRead(); // 读取socket传入的数据

// 界面事件系统生成的槽函数
void on_actJoin_triggered(); // 加入组播

void on_actLeave_triggered(); // 离开组播

void on_btnMulticast_clicked(); // 发送组播消息

(3)构造函数中初始化socket,连接信号槽

    udpSocket = new QUdpSocket(this); // 用于与连接的客户端通讯的QUdpSocket
	// Multicast路由层次,1表示只在同一局域网内
    // 组播TTL: 生存时间,每跨1个路由会减1,多播无法跨过大多数路由所以为1
    // 默认值是1,表示数据包只能在本地的子网中传送。
    udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, 1);
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));

将MulticastTtlOption设置为1,MulticastTtlOption是UDP组播数据报的生存周期,数据报每跨一个路由会减1,缺省值为1,表示多播数据只能在同一路由下的局域网内传播。

(4)加入组播

void MainWindow::on_actJoin_triggered()
{
    QString IP = ui->comboIP->currentText();
    groupAddress = QHostAddress(IP); // 多播组地址
    quint16 groupPort=ui->spinPort->value(); // 端口
    
    // QHostAddress::AnyIPv4 与此地址绑定的socket将仅侦听IPv4交互
    // groupPort,多播组统一的一个端口
	// QUdpSocket::ShareAddress 允许其他服务绑定到相同的地址和端口
	// QUdpSocket::ReuseAddressHint 向QAbstractSocket提供提示,提示它应尝试重新绑定服务,即使地址和端口已被另一个套接字绑定。在Windows和Unix上,这相当于SO_REUSEADDR套接字选项。
	// QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint 组合使用才能在本机同时启动多个程序绑定相同端口,适合没有局域网只有一台电脑的本地测试使用
    if (udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint)) //先绑定端口
    {
        udpSocket->joinMulticastGroup(groupAddress); //加入IP地址为groupAddress的多播组,绑定端口groupPort进行通信
        ui->plainTextEdit->appendPlainText("**加入组播成功");
        ui->plainTextEdit->appendPlainText("**组播地址IP:"+IP);
        ui->plainTextEdit->appendPlainText("**绑定端口:"+QString::number(groupPort));
        ui->actJoin>setEnabled(false);
        ui->actLeave->setEnabled(true);
        ui->comboIP->setEnabled(false);
    }
    else
        ui->plainTextEdit->appendPlainText("**绑定端口失败");
}

(5)发送组播消息

void MainWindow::on_btnMulticast_clicked()
{
    quint16 groupPor t= ui->spinPort->value();
    QString msg = ui->editMsg->text();
    QByteArray datagram = msg.toUtf8();

    udpSocket->writeDatagram(datagram,groupAddress,groupPort);
    ui->plainTextEdit->appendPlainText("[multicst] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();
}

(6)读取数据报

// 由readyRead()信号触发的槽函数。
// 绑定端口后,只要有UDP数据报到达指定的地址和端口,就会发出信号QUdpSocket::readyRead()
void MainWindow::onSocketReadyRead()
{
    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress peerAddr;
        quint16 peerPort;
        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);
    }
}

(7)退出组播

void MainWindow::on_actLeave_triggered()
{
    udpSocket->leaveMulticastGroup(groupAddress);// 退出组播
    udpSocket->abort(); // 中止当前连接并重置套接字。与disconnectFromHost()不同,此函数会立即关闭套接字,丢弃写入缓冲区中的所有挂起数据。
    ui->actJoin->setEnabled(true);
    ui->actLeave->setEnabled(false);
    ui->comboIP->setEnabled(true);
    ui->plainTextEdit->appendPlainText("**已退出组播,解除端口绑定");
}

4. 程序演示

Qt网络-UDP组播(三)_第1张图片
可以同时启动多个程序,加入相同组播地址,绑定相同端口,即可收到组内的任何用户的消息,自己主机上发送的消息自己也会收到。

你可能感兴趣的:(Qt,qt,udp)