Qt:84---Demo(UDP组播通信演示案例)

因为UDP通信为点对点,所双方的程序相同,共用一份代码

第一步:

  • 创建一个基于QMainWindow的应用程序,类名采取默认值。并设计窗体

第二步:

  • 类的设计
//只列出了自己写的代码,默认的代码省略了
#include <QUdpSocket>
#include <QHostInfo>
#include <QLabel>

class MainWindow : public QMainWindow
{
private:
    QLabel *LabSocketState;//socket状态显示标签
    QUdpSocket *udpSocket; //UDP套接字
    QHostAddress groupAddress; //组播地址
    QString getLocalIP();  //获取本地目标地址
private slots:
    //自定义槽函数
    void onSocketStateChange(QAbstractSocket::SocketState socketState);
    void onSocketReadyRead();
};

第三步:

  • 构造函数
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //设置spin控件可以显示的最大值
    ui->spinGroupPort->setMaximum(65535);

    //设置标签的内容并显示在状态栏和窗体标题中
    LabSocketState=new QLabel(QStringLiteral("Socket状态:"));
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    //获取本机IP地址显示在comboBox中
    QString localIp=getLocalIP();
    this->setWindowTitle(this->windowTitle()+QStringLiteral("本机IP:")+localIp);

    //设置初始化的组播地址
    ui->comGroupIp->addItem("239.255.43.21");

    //创建QUdpSocket对象
    udpSocket=new QUdpSocket(this);
    //设置socket对象的选项(MulticastLoopbackOption是组播数据报的生存期特性,此处设为数据报每跨1个路由会减1。参数2缺省值为1,表示数据报只能在同一路由的局域网内传播)
    udpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption,1);

    //绑定信号与槽
    connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(udpSocket->state());
    connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}

第四步:

  • 加入组播按钮的响应函数
void MainWindow::on_actAdd_triggered()
{
    //获取IP和端口
    QString IP=ui->comGroupIp->currentText();
    groupAddress=QHostAddress(IP);
    quint16 groupPort=ui->spinGroupPort->value();
    
    //绑定组播的端口(参数1指定地址为AnyIPv4表示端口为多播组统一的一个端口)
    if(udpSocket->bind(QHostAddress::AnyIPv4,groupPort,QUdpSocket::ShareAddress))
    {
        udpSocket->joinMulticastGroup(groupAddress);//加入组播组
        ui->plainTextEdit->appendPlainText(QStringLiteral("加入组播成功"));
        ui->plainTextEdit->appendPlainText(QStringLiteral("组播IP:")+IP);
        ui->plainTextEdit->appendPlainText(QStringLiteral("绑定端口:")+QString::number(groupPort));
        ui->actAdd->setEnabled(false);
        ui->actLeave->setEnabled(true);
        ui->comGroupIp->setEnabled(false);
    }
    else
        ui->plainTextEdit->appendPlainText(QStringLiteral("绑定端口失败"));
}
  • 退出组播按钮的响应函数
void MainWindow::on_actLeave_triggered()
{
    udpSocket->leaveMulticastGroup(groupAddress); //退出组播
    udpSocket->abort(); //重置套接字
    ui->actAdd->setEnabled(true);
    ui->actLeave->setEnabled(false);
    ui->comGroupIp->setEnabled(true);
    ui->plainTextEdit->appendPlainText(QStringLiteral("已退出组播,解除端口绑定"));
}

第五步:

  • 组播消息按钮的响应函数
void MainWindow::on_btnMulticast_clicked()
{
    //获取组播端口
    quint16 groupPort=ui->spinGroupPort->value();
   
    //获取数据,并发送组播数据
    QString msg=ui->editMsg->text();   
    QByteArray datagram=msg.toUtf8();
    udpSocket->writeDatagram(datagram,groupAddress,groupPort);

    ui->plainTextEdit->appendPlainText(QStringLiteral("[mulicast]:")+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();
}

第六步:

  • 自定义onSocketReadyRead槽函数
void MainWindow::onSocketReadyRead()
{
    //hasPendingDatagrams代表如果有数据可以读取
    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);
    }
}

第七步:

  • 自定义onSocketStateChange槽函数
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
    //socket的各种状态
    switch (socketState) {
        case QAbstractSocket::UnconnectedState:
            LabSocketState->setText(QStringLiteral("socket状态:UnconnectedState"));
            break;
        case QAbstractSocket::HostLookupState:
            LabSocketState->setText(QStringLiteral("socket状态:HostLookupState"));
            break;
        case QAbstractSocket::ConnectedState:
            LabSocketState->setText(QStringLiteral("socket状态:ConnectedState"));
            break;
        case QAbstractSocket::BoundState:
            LabSocketState->setText(QStringLiteral("socket状态:BoundState"));
            break;
        case QAbstractSocket::ClosingState:
            LabSocketState->setText(QStringLiteral("socket状态:ClosingState"));
            break;
        case QAbstractSocket::ListeningState:
            LabSocketState->setText(QStringLiteral("socket状态:ListeningState"));
            break;
    }
}

演示效果

  • 局域网的组播地址的范围是239.0.0.0~239.255.255.255。所以在构造函数中,我们给出了一个初始化的组播地址239.255.43.21
  • 且因为一台主机只能作为组播中的一员,所以如果想要实验组播,要在同一局域网的不同主机进行实验(下面是两台不同的主机,所以端口可以相同(这个端口不是自己的端口,而是组播的端口),指向同一个组播地址)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董哥的黑板报

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值