Qt5官方Demo解析集2——Multicast Sender/Receiverz

【来源】http://blog.csdn.net/cloud_castle/article/details/21606451

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873


在上篇博文中记录了Fortune Server/Client Example,那个例子基于Tcp传输协议的,Tcp是一种可靠协议,但是有时候我们并不在意数据包是否被成功投递,这种情况尤其出现在一些不断重复数据的发送上,比如每秒一次的温度,时间等。在这种情况下我们往往倾向使用Udp来发送和接收UDP数据报(datagram)。今天Multicast Sender/Receiver这个例子就是一个基于QUdpSocket实现的UDP组播发送。并且使用TTL(Time To Live)来控制网络开销。


按照惯例,看看官方介绍吧:

Demonstrates how to send messages to a multicast group
This example demonstrates how to send messages to the clients of a multicast group.



好了,那我们进主题,先看multicastsender文件包里面的sender.h:

  1. #ifndef SENDER_H  
  2. #define SENDER_H  
  3.   
  4. #include <QDialog>  
  5. #include <QHostAddress>  
  6.   
  7. QT_BEGIN_NAMESPACE  
  8. class QDialogButtonBox;  
  9. class QLabel;  
  10. class QPushButton;  
  11. class QTimer;  
  12. class QUdpSocket;  
  13. class QSpinBox;  
  14. QT_END_NAMESPACE  
  15.   
  16. class Sender : public QDialog  
  17. {  
  18.     Q_OBJECT  
  19.   
  20. public:  
  21.     Sender(QWidget *parent = 0);  
  22.   
  23. private slots:  
  24.     void ttlChanged(int newTtl);  
  25.     void startSending();  
  26.     void sendDatagram();  
  27.   
  28. private:  
  29.     QLabel *statusLabel;  
  30.     QLabel *ttlLabel;  
  31.     QSpinBox *ttlSpinBox;  
  32.     QPushButton *startButton;  
  33.     QPushButton *quitButton;  
  34.     QDialogButtonBox *buttonBox;  
  35.     QUdpSocket *udpSocket;  
  36.     QTimer *timer;  
  37.     QHostAddress groupAddress;  
  38.     int messageNo;  
  39. };  
  40.   
  41. #endif  
#ifndef SENDER_H
#define SENDER_H

#include <QDialog>
#include <QHostAddress>

QT_BEGIN_NAMESPACE
class QDialogButtonBox;
class QLabel;
class QPushButton;
class QTimer;
class QUdpSocket;
class QSpinBox;
QT_END_NAMESPACE

class Sender : public QDialog
{
    Q_OBJECT

public:
    Sender(QWidget *parent = 0);

private slots:
    void ttlChanged(int newTtl);
    void startSending();
    void sendDatagram();

private:
    QLabel *statusLabel;
    QLabel *ttlLabel;
    QSpinBox *ttlSpinBox;
    QPushButton *startButton;
    QPushButton *quitButton;
    QDialogButtonBox *buttonBox;
    QUdpSocket *udpSocket;
    QTimer *timer;
    QHostAddress groupAddress;
    int messageNo;
};

#endif
如果有上一篇博文的基础,这里就没什么好说的了。。。注意这个messageNo在源文件是作为计数使用,不是Nomessage,而是No.message。。。好的取名对理解程序是有很大帮助的。


sender.cpp:

  1. #include <QtWidgets>  
  2. #include <QtNetwork>  
  3.   
  4. #include "sender.h"  
  5.   
  6. Sender::Sender(QWidget *parent)  
  7.     : QDialog(parent)  
  8. {  
  9.     groupAddress = QHostAddress("239.255.43.21"); //IANA网络,可以作为局域网IP  
  10.   
  11.     statusLabel = new QLabel(tr("Ready to multicast datagrams to group %1 on port 45454").arg(groupAddress.toString()));  
  12.   
  13.     ttlLabel = new QLabel(tr("TTL for multicast datagrams:"));  // 控件布局  
  14.     ttlSpinBox = new QSpinBox;  
  15.     ttlSpinBox->setRange(0, 255);  
  16.   
  17.     QHBoxLayout *ttlLayout = new QHBoxLayout;  
  18.     ttlLayout->addWidget(ttlLabel);  
  19.     ttlLayout->addWidget(ttlSpinBox);  
  20.   
  21.     startButton = new QPushButton(tr("&Start"));  
  22.     quitButton = new QPushButton(tr("&Quit"));  
  23.   
  24.     buttonBox = new QDialogButtonBox;  
  25.     buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);  
  26.     buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);  
  27.   
  28.     timer = new QTimer(this);    
  29.     udpSocket = new QUdpSocket(this); // udpSocket在这里初始化  
  30.     messageNo = 1;  
  31.   
  32.     connect(ttlSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ttlChanged(int)));  
  33.     connect(startButton, SIGNAL(clicked()), this, SLOT(startSending()));  
  34.     connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));  
  35.     connect(timer, SIGNAL(timeout()), this, SLOT(sendDatagram())); // 重复性的数据发送,可以看到使用Udp的场合  
  36.   
  37.     QVBoxLayout *mainLayout = new QVBoxLayout;  
  38.     mainLayout->addWidget(statusLabel);  
  39.     mainLayout->addLayout(ttlLayout);  
  40.     mainLayout->addWidget(buttonBox);  
  41.     setLayout(mainLayout);  
  42.   
  43.     setWindowTitle(tr("Multicast Sender"));  
  44.     ttlSpinBox->setValue(1);  
  45. }  
  46.   
  47. void Sender::ttlChanged(int newTtl)  
  48. {  
  49.     udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, newTtl); // 这里是将网络设置成Multicast_TTL模式,第二个参数是TTL最大路由数  
  50. }  
  51.   
  52. void Sender::startSending()  
  53. {  
  54.     startButton->setEnabled(false);  
  55.     timer->start(1000);  
  56. }  
  57.   
  58. void Sender::sendDatagram()  
  59. {  
  60.     statusLabel->setText(tr("Now sending datagram %1").arg(messageNo));  
  61.     QByteArray datagram = "Multicast message " + QByteArray::number(messageNo); // 这里没有使用QDataStrem,因为数据无须校验。  
  62.     udpSocket->writeDatagram(datagram.data(), datagram.size(), // 调用writeDatagram函数,这里使用writeDatagram(datagram, groupAddress, 45454)也是可以的  
  63.                              groupAddress, 45454);  
  64.     ++messageNo;  
  65. }  
#include <QtWidgets>
#include <QtNetwork>

#include "sender.h"

Sender::Sender(QWidget *parent)
    : QDialog(parent)
{
    groupAddress = QHostAddress("239.255.43.21"); //IANA网络,可以作为局域网IP

    statusLabel = new QLabel(tr("Ready to multicast datagrams to group %1 on port 45454").arg(groupAddress.toString()));

    ttlLabel = new QLabel(tr("TTL for multicast datagrams:"));  // 控件布局
    ttlSpinBox = new QSpinBox;
    ttlSpinBox->setRange(0, 255);

    QHBoxLayout *ttlLayout = new QHBoxLayout;
    ttlLayout->addWidget(ttlLabel);
    ttlLayout->addWidget(ttlSpinBox);

    startButton = new QPushButton(tr("&Start"));
    quitButton = new QPushButton(tr("&Quit"));

    buttonBox = new QDialogButtonBox;
    buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

    timer = new QTimer(this);  
    udpSocket = new QUdpSocket(this); // udpSocket在这里初始化
    messageNo = 1;

    connect(ttlSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ttlChanged(int)));
    connect(startButton, SIGNAL(clicked()), this, SLOT(startSending()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(timer, SIGNAL(timeout()), this, SLOT(sendDatagram())); // 重复性的数据发送,可以看到使用Udp的场合

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addLayout(ttlLayout);
    mainLayout->addWidget(buttonBox);
    setLayout(mainLayout);

    setWindowTitle(tr("Multicast Sender"));
    ttlSpinBox->setValue(1);
}

void Sender::ttlChanged(int newTtl)
{
    udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption, newTtl); // 这里是将网络设置成Multicast_TTL模式,第二个参数是TTL最大路由数
}

void Sender::startSending()
{
    startButton->setEnabled(false);
    timer->start(1000);
}

void Sender::sendDatagram()
{
    statusLabel->setText(tr("Now sending datagram %1").arg(messageNo));
    QByteArray datagram = "Multicast message " + QByteArray::number(messageNo); // 这里没有使用QDataStrem,因为数据无须校验。
    udpSocket->writeDatagram(datagram.data(), datagram.size(), // 调用writeDatagram函数,这里使用writeDatagram(datagram, groupAddress, 45454)也是可以的
                             groupAddress, 45454);
    ++messageNo;
}
Sender端代码就是这样了,是不是觉得官方demo也不难理解~

ok,继续来看receiver.h和receiver.cpp:

receiver.h:

  1. #ifndef RECEIVER_H  
  2. #define RECEIVER_H  
  3.   
  4. #include <QDialog>  
  5. #include <QHostAddress>  
  6.   
  7. QT_BEGIN_NAMESPACE  
  8. class QLabel;  
  9. class QPushButton;  
  10. class QUdpSocket;  
  11. QT_END_NAMESPACE  
  12.   
  13. class Receiver : public QDialog  
  14. {  
  15.     Q_OBJECT  
  16.   
  17. public:  
  18.     Receiver(QWidget *parent = 0);  
  19.   
  20. private slots:  
  21.     void processPendingDatagrams();  
  22.   
  23. private:  
  24.     QLabel *statusLabel;  
  25.     QPushButton *quitButton;  
  26.     QUdpSocket *udpSocket;  
  27.     QHostAddress groupAddress;  
  28. };  
#ifndef RECEIVER_H
#define RECEIVER_H

#include <QDialog>
#include <QHostAddress>

QT_BEGIN_NAMESPACE
class QLabel;
class QPushButton;
class QUdpSocket;
QT_END_NAMESPACE

class Receiver : public QDialog
{
    Q_OBJECT

public:
    Receiver(QWidget *parent = 0);

private slots:
    void processPendingDatagrams();

private:
    QLabel *statusLabel;
    QPushButton *quitButton;
    QUdpSocket *udpSocket;
    QHostAddress groupAddress;
};

不用说什么了吧。

receiver.cpp:
  1. #include <QtWidgets>  
  2. #include <QtNetwork>  
  3.   
  4. #include "receiver.h"  
  5.   
  6. Receiver::Receiver(QWidget *parent)  
  7.     : QDialog(parent)  
  8. {  
  9.     groupAddress = QHostAddress("239.255.43.21"); // 与发送端取同样的IP地址  
  10.   
  11.     statusLabel = new QLabel(tr("Listening for multicasted messages"));  
  12.     quitButton = new QPushButton(tr("&Quit"));  
  13.   
  14.     udpSocket = new QUdpSocket(this);  
  15.     udpSocket->bind(QHostAddress::AnyIPv4, 45454, QUdpSocket::ShareAddress); // 绑定了任意的IPv4地址,45454端口,并允许其他服务使用该端口  
  16.     udpSocket->joinMulticastGroup(groupAddress); // 以操作系统默认接口加入Multicast网络组  
  17.   
  18.     connect(udpSocket, SIGNAL(readyRead()), // 数据流过来触发readyRead()信号  
  19.             this, SLOT(processPendingDatagrams()));  
  20.     connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));  
  21.   
  22.     QHBoxLayout *buttonLayout = new QHBoxLayout; // 按钮居中  
  23.     buttonLayout->addStretch(1);  
  24.     buttonLayout->addWidget(quitButton);  
  25.     buttonLayout->addStretch(1);  
  26.   
  27.     QVBoxLayout *mainLayout = new QVBoxLayout;  
  28.     mainLayout->addWidget(statusLabel);  
  29.     mainLayout->addLayout(buttonLayout);  
  30.     setLayout(mainLayout);  
  31.   
  32.     setWindowTitle(tr("Multicast Receiver"));  
  33. }  
  34.   
  35. void Receiver::processPendingDatagrams()  
  36. {  
  37.     while (udpSocket->hasPendingDatagrams()) { // 是否有待处理的信号  
  38.         QByteArray datagram;  
  39.         datagram.resize(udpSocket->pendingDatagramSize()); // 以数据包的大小初始化datagram  
  40.         udpSocket->readDatagram(datagram.data(), datagram.size()); // 直接读就可以了  
  41.         statusLabel->setText(tr("Received datagram: \"%1\"")   
  42.                              .arg(datagram.data()));  
  43.     }  
  44. }  
#include <QtWidgets>
#include <QtNetwork>

#include "receiver.h"

Receiver::Receiver(QWidget *parent)
    : QDialog(parent)
{
    groupAddress = QHostAddress("239.255.43.21"); // 与发送端取同样的IP地址

    statusLabel = new QLabel(tr("Listening for multicasted messages"));
    quitButton = new QPushButton(tr("&Quit"));

    udpSocket = new QUdpSocket(this);
    udpSocket->bind(QHostAddress::AnyIPv4, 45454, QUdpSocket::ShareAddress); // 绑定了任意的IPv4地址,45454端口,并允许其他服务使用该端口
    udpSocket->joinMulticastGroup(groupAddress); // 以操作系统默认接口加入Multicast网络组

    connect(udpSocket, SIGNAL(readyRead()), // 数据流过来触发readyRead()信号
            this, SLOT(processPendingDatagrams()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));

    QHBoxLayout *buttonLayout = new QHBoxLayout; // 按钮居中
    buttonLayout->addStretch(1);
    buttonLayout->addWidget(quitButton);
    buttonLayout->addStretch(1);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addLayout(buttonLayout);
    setLayout(mainLayout);

    setWindowTitle(tr("Multicast Receiver"));
}

void Receiver::processPendingDatagrams()
{
    while (udpSocket->hasPendingDatagrams()) { // 是否有待处理的信号
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize()); // 以数据包的大小初始化datagram
        udpSocket->readDatagram(datagram.data(), datagram.size()); // 直接读就可以了
        statusLabel->setText(tr("Received datagram: \"%1\"") 
                             .arg(datagram.data()));
    }
}
Ok,今天的学习先到这里吧~



2
0
 
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值