【来源】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:
- #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
#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:
- #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;
- }
#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:
- #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;
- };
#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:- #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()));
- }
- }
#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