本系列所有文章可以在這里查看[http://blog.csdn.net/cloud_castle/article/category/2123873](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
~~~
如果有上一篇博文的基礎,這里就沒什么好說的了。。。注意這個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;
}
~~~
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;
};
~~~
不用說什么了吧。
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()));
}
}
~~~
Ok,今天的學習先到這里吧~
- 前言
- 1——Fortune Server/Client
- 2——Multicast Sender/Receiverz
- 3——Broadcast Sender/Receiver
- 4——Blocking Fortune Client
- 5——Threaded Fortune Server
- 5(總結)——Fortune例程的各個實現區別
- 6——Loopback Example
- 7——Analog Clock Example
- 8——Shaped Clock Example
- 9——Analog Clock Window Example
- 10——Qt Quick Particles Examples - Emitters
- 11——Qt Quick Particles Examples - Affectors
- 12——Qt Quick Particles Examples - CustomParticles
- 13——Qt Quick Particles Examples - Image Particles
- 14——Qt Quick Particles Examples - System
- 15——Chapter 1: Creating a New Type
- 16——Chapter 2: Connecting to C++ Methods and Signals
- 17——Chapter 3: Adding Property Bindings
- 18——Chapter 4: Using Custom Property Types
- 19——Chapter 5: Using List Property Types
- 20——Chapter 6: Writing an Extension Plugin
- 21——Extending QML - Adding Types Example
- 22——Extending QML - Object and List Property Types Example
- 23——Extending QML - Inheritance and Coercion Example
- 24——Extending QML - Default Property Example
- 25——Extending QML - Methods Example
- 26——Extending QML - Grouped Properties Example
- 27——Extending QML - Attached Properties Example
- 28——Extending QML - Signal Support Example
- 29——Extending QML - Property Value Source Example
- 30——Extending QML - Binding Example
- 31——StocQt
- 32——Qt Quick Examples - Threading
- 33——Qt Quick Examples - Window and Screen
- 34——Concentric Circles Example
- 35——Music Player
- 36——Wiggly Example
- 37——Vector Deformation