Qt5官方Demo解析集3——Broadcast Sender/Receiver

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


上次在该系列第一篇博文里提到QTcp的同步构建方式,这个例子涉及线程等,知识点比较多。我们还是由浅入深,今天再看个简单的例子吧~

按例看下Broadcast Sender Example的介绍吧,这对第一时间了解这个例程是有好处的~

Demonstrates how to broadcast information to multiple clients on a local network.
This example uses Qt Network APIs to demonstrate how to broadcast messages to multiple clients over a local network.



main主函数没有特别的东西,来看sender.h:

#ifndef SENDER_H
#define SENDER_H

#include <QWidget>

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

class Sender : public QWidget
{
    Q_OBJECT

public:
    Sender(QWidget *parent = 0);

private slots:
    void startBroadcasting();
    void broadcastDatagram();

private:
    QLabel *statusLabel;
    QPushButton *startButton;
    QPushButton *quitButton;
    QDialogButtonBox *buttonBox;
    QUdpSocket *udpSocket;
    QTimer *timer;
    int messageNo;
};

#endif
可以发现这个头文件像Multicast Sender的头文件一样简单,甚至比它更简单。因为它连QHostAddress成员都没有。


sender.cpp:

#include <QtWidgets>
#include <QtNetwork>

#include "sender.h"

Sender::Sender(QWidget *parent)
    : QWidget(parent)
{
    statusLabel = new QLabel(tr("Ready to broadcast datagrams on port 45454"));
    statusLabel->setWordWrap(true); // 这个属性的设置使得statusLabel的文字可以在合适的位置换行

    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);
//! [0]
    udpSocket = new QUdpSocket(this);
//! [0]
    messageNo = 1;

    connect(startButton, SIGNAL(clicked()), this, SLOT(startBroadcasting()));
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(timer, SIGNAL(timeout()), this, SLOT(broadcastDatagram()));

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

    setWindowTitle(tr("Broadcast Sender"));
}

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

void Sender::broadcastDatagram()
{
    statusLabel->setText(tr("Now broadcasting datagram %1").arg(messageNo));
//! [1]
    QByteArray datagram = "Broadcast message " + QByteArray::number(messageNo);
    udpSocket->writeDatagram(datagram.data(), datagram.size(), // 第(1)点
                             QHostAddress::Broadcast, 45454);
//! [1]
    ++messageNo;
}
第一点,发送数据的语句就这一条,与Multicast唯一的区别在于使用了一个QHostAddress的枚举变量Broadcast,它相当于QHostAddress(“255,255,255,255”)。


好了,来看Broadcast Receiver的实现。receiver.h:

#ifndef RECEIVER_H
#define RECEIVER_H

#include <QWidget>

QT_BEGIN_NAMESPACE
class QLabel;
class QPushButton;
class QUdpSocket;
class QAction;
QT_END_NAMESPACE

class Receiver : public QWidget
{
    Q_OBJECT

public:
    Receiver(QWidget *parent = 0);

private slots:
    void processPendingDatagrams();

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

#endif


receiver.cpp:

#include <QtWidgets> // 第(1)点
#include <QtNetwork>

#include "receiver.h"

Receiver::Receiver(QWidget *parent)
    : QWidget(parent)
{
    statusLabel = new QLabel(tr("Listening for broadcasted messages"));
    statusLabel->setWordWrap(true);

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

//! [0]
    udpSocket = new QUdpSocket(this);
    udpSocket->bind(45454, QUdpSocket::ShareAddress); // 绑定端口,共享地址模式
//! [0]

//! [1]
    connect(udpSocket, SIGNAL(readyRead()),
            this, SLOT(processPendingDatagrams()));
//! [1]
    connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));

    QHBoxLayout *buttonLayout = new QHBoxLayout; // 以控件为Layout命名,而不是Layout1,Layout2...
    buttonLayout->addStretch(1);
    buttonLayout->addWidget(quitButton);
    buttonLayout->addStretch(1);

    QVBoxLayout *mainLayout = new QVBoxLayout; // 最外层的布局mainLayout
    mainLayout->addWidget(statusLabel);
    mainLayout->addLayout(buttonLayout);
    setLayout(mainLayout);

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

void Receiver::processPendingDatagrams() // 接收端的处理函数与Multicast一模一样
{
//! [2]
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(), datagram.size());
        statusLabel->setText(tr("Received datagram: \"%1\"")
                             .arg(datagram.data()));
    }
//! [2]
}
第一点,个人不推荐这种头文件的包含方式,官方Demo为了简明这样做了,但这样会使包含的文件过多,最好用到什么包含什么,虽然会多写几个#include,但是预编译结束后文件体积会小很多。而且#include<QtWidgets/QLabel>优于#include<QLabel>,这样头文件的层次更清晰。

好了,其实这个例子与上一个Multicast Sender/Receiver 基本没有多大区别,但是我们读例程并不只是关注它核心功能的实现,更多的在于细节的处理。细节决定成败嘛~




你可能感兴趣的:(qt,NetWork,Qt5官方Demo解析集)