Qt基于UDP的网络广播程序

        用户数据报协议(User Data Protocol,UDP)是一种简单轻量级、不可靠、面向数据报、无连接的传输层协议,可以应用在可靠性不是十分重要的场合,如短消息、广播信息等。

        适合应用的情况有一下几种:

  • 网络数据大多为短消息;
  • 拥有大量客户端;
  • 对数据安全性无特殊要求;
  • 网络负担非常重,但对响应速度要求高。

一、UDP协议工作原理

        如图所示,UDP客户端向UDP服务器发送一定长度的请求报文,报文大小的限制与各系统的协议实现有关,但不得超过其下层IP协议规定的64KB;UDP服务器同样以报文形式作出响应。如果服务器未收到此请求,客户端不会进行重发,因此报文的传输是不可靠的。

二、UDP编程模型

        下面介绍基于UDP协议的经典编程模型,程序编写的通用流程如图所示。

         可以看出,在UDP方式下客户端并不与服务器建立连接,它只负责调用发送函数向服务器发出数据报。类似地,服务器也不从客户端接收连接,只负责调用接收函数,等待来自某客户端的数据到达。

        Qt中通过QUdpSocket类实现UDP协议的编程。接下来通过一个实例,介绍如何实现基于UDP协议的广播应用,它由UDP服务器和UDP客户端两部分组成。

三、UDP服务器编程实例

  1. 工程文件
    QT += network
  2. 头文件
    #include <QDialog>
    #include <QLabel>
    #include <QLineEdit>
    #include <QPushButton>
    #include <QVBoxLayout>
    #include <QUdpSocket>
    #include <QTimer>
    #include <QHostAddress>
    
    class UdpServer : public QDialog
    {
        Q_OBJECT
    
    public:
        UdpServer(QWidget *parent = 0,Qt::WindowFlags f=0);
        ~UdpServer();
    
    public slots:
        void StartBtnClicked();
        void timeout();
    
    private:
        QLabel *TimerLabel;
        QLineEdit *TextLineEdit;
        QPushButton *StartBtn;
        QVBoxLayout *mainLayout;
    
        int port;
        bool isStarted;
        QUdpSocket *udpSocket;
        QTimer *timer;
    };
    

  3. 源文件
    #include "udpserver.h"
    
    UdpServer::UdpServer(QWidget *parent,Qt::WindowFlags f)
        : QDialog(parent,f)
    {
        setWindowTitle(tr("UDP Server"));
    
        TimerLabel = new QLabel(tr("计时器:"),this);
        TextLineEdit = new QLineEdit(this);
        StartBtn = new QPushButton(tr("开始"),this);
        mainLayout = new QVBoxLayout(this);
        mainLayout->addWidget(TimerLabel);
        mainLayout->addWidget(TextLineEdit);
        mainLayout->addWidget(StartBtn);
    
        port = 5555;
        isStarted = false;
        udpSocket = new QUdpSocket(this);
        timer = new QTimer(this);
        connect(StartBtn,SIGNAL(clicked(bool)),this,SLOT(StartBtnClicked()));
        connect(timer,SIGNAL(timeout()),this,SLOT(timeout()));
    }
    
    UdpServer::~UdpServer()
    {
    }
    
    void UdpServer::StartBtnClicked()
    {
        if(!isStarted)
        {
            StartBtn->setText(tr("停止"));
            timer->start(1000);
            isStarted = true;
        }
        else
        {
            StartBtn->setText(tr("开始"));
            isStarted = false;
            timer->stop();
        }
    }
    
    void UdpServer::timeout()
    {
        QString msg = TextLineEdit->text();
        int length = 0;
        if(msg=="") return;
        QByteArray sendBuff = msg.toUtf8();
        length=udpSocket->writeDatagram(sendBuff,sendBuff.length(), QHostAddress::Broadcast,port);
        if(length !=msg.length()) return;
    }
    

其中,

  • setWindowTitle(tr("UDP Server")):设置窗体的标题。
  • TimerLabel = new QLabel(tr("计时器: "),this)到mainLayout->addWidget(StartBtn)这段代码:初始化了各个控件并设置布局。
  • port =5555:设置UDP的端口号参数,服务器定时向此端口发送广播信息。
  • timer = new QTimer(this):创建一个QUdpSocket。
  • connect(timer,SIGNAL(timeout()),this,SLOT(timeout())):定时发送广播信息。
  • QHostAddress::Broadcast:指定向广播地址发送。

注意:发送消息时需要转成UTF-8,否则发送中文字符时客户端会受到乱码!

四、UDP客户端编程实例

  1. 工程文件
    QT += network

  2. 头文件
    #include <QDialog>
    #include <QVBoxLayout>
    #include <QTextEdit>
    #include <QPushButton>
    #include <QMessageBox>
    #include <QUdpSocket>
    #include <QHostAddress>
    
    class UdpClient : public QDialog
    {
        Q_OBJECT
    
    public:
        UdpClient(QWidget *parent = 0,Qt::WindowFlags f=0);
        ~UdpClient();
    
    public slots:
        void CloseBtnClicked();
        void dateReceived();
    
    private:
        QTextEdit *ReceiveTextEdit;
        QPushButton *CloseBtn;
        QVBoxLayout *mainLayout;
    
        int port;
        QUdpSocket *udpSocket;
    };
    

  3. 源文件
    #include "udpclient.h"
    
    UdpClient::UdpClient(QWidget *parent,Qt::WindowFlags f)
        : QDialog(parent,f)
    {
        setWindowTitle(tr("UDP Client"));
    
        ReceiveTextEdit = new QTextEdit(this);
        CloseBtn = new QPushButton(tr("close"),this);
        mainLayout = new QVBoxLayout(this);
        mainLayout->addWidget(ReceiveTextEdit);
        mainLayout->addWidget(CloseBtn);
    
        port = 5555;
        udpSocket = new QUdpSocket(this);
        connect(CloseBtn,SIGNAL(clicked(bool)),this,SLOT(CloseBtnClicked()));
        connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dateReceived()));
    
        bool result = udpSocket->bind(port);
        if(!result)
        {
            QMessageBox::information(this,tr("error"),tr("udp socket create error!"));
            return;
        }
    }
    
    UdpClient::~UdpClient()
    {
    }
    
    void UdpClient::CloseBtnClicked()
    {
        close();
    }
    
    void UdpClient::dateReceived()
    {
        while (udpSocket->hasPendingDatagrams())
        {
            QByteArray datagram;
            datagram.resize(udpSocket->pendingDatagramSize());
    
            udpSocket->readDatagram(datagram.data(),datagram.size());
            QString msg = QString::fromUtf8(datagram.data());
            ReceiveTextEdit->insertPlainText(msg);
        }
    }

其中,

  • setWindowTitle(tr("UDPClient"')):设置窗体的标题。
  • ReceiveTextEdit = new QTextEdit(this)到 mainLayout->addWidget(CloseBtn)这段代码:初始化各个控件并设置布局。
  • port =5555:设置UDP的端口号参数,指定在此端口上监听数据。
  • udpSocket = new QUdpSocket(this):创建一个QUdpSocket。
  • connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dateReceived())) :连接QIODevice的readyRead()信号。QUdpSocket 也是一个IO设备,从QIODevice继承而来,当有数据到达I/O设备时,发出readyRead()信号。
  • bool result=udpSocket->bind(port):绑定到指定的端口上。
  • while(udpSocket->hasPendingDatagrams()):判断UdpSocket中是否有数据报可读,hasPendingDatagrams()方法在至少有一个数据报可读时返回true,否则返回false。
  • QByteArray datagram到udpSocket->readDatagram(datagram.data(),datagram.size())这段代码:实现了读取第一个数据报,pendingDatagramSize()可以获得第一个数据报的长度。
  • ReceiveTextEdit->insertPlainText(msg):显示数据内容。

最终效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值