一、基础知识
QUdpSocket 类:这个类专门用来做网络之间的数据广播 ,所谓的数据广播:只有一台设备负责发送数据,并且该设备不接受数据 ,剩余所有设备负责接受数据,并且不能发送数据
QUdpSocket的操作步骤: ① 创建QUdpSocket对象 ② 绑定广播地址和端口号
注意,绑定形式不同,广播的形式也不同的 ,广播分为2种形式: 1:广播形式 2:组播形式
这两种形式的唯一区别在于:广播默认广播地址为 255.255.255.255,组播的话,需要自己填写一个广播地址,并且使用的组播的情况下,数据的接收方需要加入该组播地址(广播的话,不需要加入地址) 所以,绑定ip地址和端口号的函数,也会有2个不同的形式
广播:bool QAbstractSocket::bind(quint16 port = 0, BindMode mode = DefaultForPlatform) port:端口号,不需要填广播地址,默认为 255.255.255.255
mode:套接字形式,一般选择QAbstractSocket::ReuseAddressHint
组播:bind(const QHostAddress &address, quint16 port = 0, BindMode mode = DefaultForPlatform)
address:组播地址,范围为 224.0.0.1~255.255.255.254 ,这里应该写 QHostAddress::AnyIPv4 port:同上
mode:同上
注意,bind函数是广播的接受方调用,根据情况还需要调用加入广播组 ,广播的发送方,在发送数据的时候,明确一下广播地址和port即可
bool joinMulticastGroup(const QHostAddress &groupAddress) 参数填写广播组地址即可
关于广播的数据发送: 注意QTcpSocket 和 QUdpSocket,他们的套接字类型是不一样的,所以数据发送的函数就不一样的
一个叫数据报类型 writeDataGram 和 readDataGram
例如:qint64 writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)
data:想要发送的数据
size:发送的数据的尺寸
address:将数据发送到的广播地址
port:将数据发送到的地方的端口号
另一个叫字节流类型 write和read
二,代码实现
1.创建一个QT文件,在.Pro文件中添加 QT += network, 这一步不可缺少,没有这一步,QT就无法连接网络编程相关的头文件
2.点击widget.h头文件,添加两个QUdpSocket 类的指针和两个槽函数,关键的头文件<QUdpSocket>不能忘记,如果第一步没做,这个头文件也就无法使用
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QUdpSocket>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked(); // 按钮的槽函数,点击按钮后发送信号
private:
Ui::Widget *ui;
QUdpSocket* reciver; //QUdpSocket对象,接收
QUdpSocket* sender; //QUdpSocket对象, 发送
public slots:
void onReadyRead(); //自定义的槽函数,当接收方接收到信号时触发
};
#endif // WIDGET_H
3.点击widget.cpp文件,将功能完善,相应的函数原型以注释
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
sender = new QUdpSocket(this);// 在未来发送数据的时候,明确ip和port即可
reciver = new QUdpSocket(this);// 需要绑定一下接受数据的ip和port,根据情况不同,还需要加入广播组
// 广播代码
//reciver->bind(12345,QUdpSocket::ReuseAddressHint); // 端口号 套接字形式
// 组播代码
reciver->bind(QHostAddress::AnyIPv4,12345,QUdpSocket::ReuseAddressHint); //组播地址 端口号 套接字形式
reciver->joinMulticastGroup(QHostAddress("224.0.0.1")); //广播接收方接收来自地址发出的信号
QObject::connect(reciver,SIGNAL(readyRead()),this,SLOT(onReadyRead())); //获取信号:void QIODevice::readyRead()后,执行自定义的槽函数
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked() //按钮槽函数的实现
{
QString str = ui->lineEdit->text(); //获取行编辑器中的文字
// 广播
//sender->writeDatagram(str.toLocal8Bit(),QHostAddress::Broadcast,12345); //qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddress &address, quint16 port)
// 组播
sender->writeDatagram(str.toLocal8Bit(),QHostAddress("224.0.0.1"),12345); //发送信号 字符串转化成本地八位表示,QByteArray QString::toLocal8Bit() const
reciver->close(); // 广播方,也就是数据发送方,不通过reciver接受数据,直接通过本地获取数据
ui->textEdit->append(str);
ui->lineEdit->clear();
}
void Widget::onReadyRead() //自定义槽函数的实现
{
int size = reciver->pendingDatagramSize(); //获取接受到的数据的大小,QTcpSocket是bytesAvalible , qint64 QUdpSocket::pendingDatagramSize() const
char buf[size+1] = {0};
reciver->readDatagram(buf,size); //接收数据,限定大小 qint64 QUdpSocket::readDatagram(char *data, qint64 maxSize, QHostAddress *address = Q_NULLPTR, quint16 *port = Q_NULLPTR)
QString str = QString::fromLocal8Bit(buf); //将字符数组转化QString类型 QString QString::fromLocal8Bit(const char *str, int size = -1)
ui->textEdit->append(str);
}
4.widget.ui文件的设置
三、效果验证
1.编译成功后,点击三次运行,构建三个窗口类对象,在窗口一中输入“多学多练”,窗口二和窗口三同时展现出“多学多练”
2.实现广播功能,效果实现!
四、扩展功能
如果想要界面美观化,可添加资源文件,修改UI文件,如果想扩展功能,可在cpp文件中添加相应功能代码