企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
本系列所有文章可以在这里查看[http://blog.csdn.net/cloud_castle/article/category/2123873](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优于#include,这样头文件的层次更清晰。 好了,其实这个例子与上一个Multicast Sender/Receiver 基本没有多大区别,但是我们读例程并不只是关注它核心功能的实现,更多的在于细节的处理。细节决定成败嘛~