简述:
UDP(User Data Protocol),用户数据报协议,是一种简单轻量级、不可靠、面向数据报、无连接的传输层协议,可以应用在可靠性不是十分重要的场合,如短消息、广播信息等。
适用于以下几种情况:
同样,如果要在Qt 进行网络编程首先需要在 .pro文件添加: QT += network。Qt 中通过 QUdpSocket类实现UDP 协议的编程。A . 网络数据大多为短消息。
B . 拥有大量客户端
C . 对数据安全性无特殊要求
D . 网络负担非常重,但对响应速度要求高。
本文介绍一个基于 UDP 协议的广播应用 ,它由UDP 服务器和 UDP 客户端两部分组成。
其实,UDP没有特定的server端 和 client,简单来说就是向特定的ip发送报文,所以,也可以分为发送端和接收端。
QUdpSocket类允许发送和接收 UDP 数据报,继承自QAbstractSocket 。QUdpSocket 支持IPv4 广播。QUdpSocket 还支持多播。
操作系统:windows 7
Qt构建套件:qt-opensource-windows-x86-mingw530-5.7.0.exe
Qt Creator版本:4.0.2
1、 UDP 协议工作原理及编程模型
1 > UDP 协议工作原理
UDP 客户端向 UDP 服务器发送一定长度的请求报文,报文大小的限制与各系统的协议实现有关,但不得超过其下层 IP 协议规定的64KB;UDP服务器同样以报文形式作出响应。如果服务器未收到此请求,客户端不会进行重发,因此报文的传输是不可靠的。
例如,常用的聊天工具------腾讯QQ软件就是使用UDP协议发送信息的,因此有时会出现收不到信息的情况。
2 > UDP 编程模型
基于UDP 协议的经典编程模型,程序编写的通用流程如下:
由上图可知,在 UDP 方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发出数据报。同样,服务器也不与客户端接收连接,只负责调用接收函数,等待来自某客户端的数据到达。
2、 UDP 接收端
Qt 的 UdpSocket 接收消息原则:
A . new一个UdpSocket
B . 调用UdpSocket的bind方法,同时指定端口号
C . 使用 connect 将接收消息函数和UdpSocket对象做关联
D . 在接受消息槽函数当中调用 readDatagram 接收消息
udpclient.h
#ifndef UDPCLIENT_H #define UDPCLIENT_H #include <QDialog> #include <QVBoxLayout> #include <QTextEdit> #include <QPushButton> #include <QUdpSocket> class UdpClient : public QDialog { Q_OBJECT public: UdpClient(QWidget *parent = 0,Qt::WindowFlags f=0); ~UdpClient(); public slots: void CloseBtnClicked(); void dataReceived(); private: QTextEdit *ReceiveTextEdit; QPushButton *CloseBtn; QVBoxLayout *mainLayout; int port; QUdpSocket *udpSocket; }; #endif // UDPCLIENT_H
udpclient.cpp
#include "udpclient.h" #include <QMessageBox> #include <QHostAddress> 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); connect(CloseBtn,SIGNAL(clicked()),this,SLOT(CloseBtnClicked())); port =5555;//设置UDP的端口号参数,指定在此端口上监听数据 udpSocket = new QUdpSocket(this); //创建一个UdpSocket //连接QIODevice的readyRead()信号,readyRead()表示有消息到来这个信号, connect(udpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived())); //指定绑定端口号,接收消息必须绑定端口号,发送消息则不需要绑定 bool result=udpSocket->bind(port);//绑定到指定的端口上 //取消绑定端口号使用:udpsocket->close()方法 if(!result) { QMessageBox::information(this,tr("error"),tr("udp socket create error!")); return; } } UdpClient::~UdpClient() { } void UdpClient::CloseBtnClicked() { close(); } void UdpClient::dataReceived() { //判断UdpSocket中是否有数据可读 while(udpSocket->hasPendingDatagrams()) { //实现读取数据报 QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); udpSocket->readDatagram(datagram.data(),datagram.size()); QString msg=datagram.data(); ReceiveTextEdit->insertPlainText(msg); } }
3、UDP 发送端
Qt 的 UdpSocket 发送消息:
A . new 一个 UdpSocket
B . 调用 writeDatagram 发送消息
udpserver.h
#ifndef UDPSERVER_H #define UDPSERVER_H #include <QDialog> #include <QLabel> #include <QLineEdit> #include <QPushButton> #include <QVBoxLayout> #include <QUdpSocket> #include <QTimer> 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; }; #endif // UDPSERVER_H
udpserver.cpp#include "udpserver.h" #include <QHostAddress> 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); connect(StartBtn,SIGNAL(clicked()),this,SLOT(StartBtnClicked())); port =5555; //设置UDP的端口号参数,服务器定时向此端口发送广播信息 isStarted=false; udpSocket = new QUdpSocket(this); //创建一个UdpSocket //定时发送广播信息 timer = new QTimer(this); 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(); } } //timeout()函数完成了向端口发送广播信息的功能 void UdpServer::timeout() { QString msg = TextLineEdit->text(); int length=0; if(msg=="") { return; } //QHostAddress::Broadcast 指定向广播地址发送,可以改成固定IP,则表示向特定IP发送 if((length=udpSocket->writeDatagram(msg.toLatin1(),msg.length(),QHostAddress::Broadcast,port))!=msg.length()) { return; } }
4、运行