UDP协议详解与QUdpSocket编程

UDP报头由4个域组成,其中每个域各占用2个字节,具体如下: 端口号 ,目标端口号 ,数据报长度 ,校验值 
UDP协议使用端口号为不同的应用保留其各自的数据传输通道。UDP和TCP协议正是采用这一机制实现对同一时刻内多项应用同时发送和接收数据的支持。数据发送一方(可以是客户端或服务器端)将UDP数据报通过源端口发送出去,而数据接收一方则通过目标端口接收数据。有的网络应用只能使用预先为其预留或注册的静态端口;而另外一些网络应用则可以使用未被注册的动态端口。因为UDP报头使用两个字节存放端口号,所以端口号的有效范围是从0到65535。一般来说,大于49151的端口号都代表动态端口。 

数据报的长度是指包括报头和数据部分在内的总的字节数。因为报头的长度是固定的,所以该域主要被用来计算可变长度的数据部分(又称为数据负载)。数据报的最大长度根据操作环境的不同而各异。从理论上说,包含报头在内的数据报的最大长度为65535字节。不过,一些实际应用往往会限制数据报的大小,有时会降低到8192字节。 

UDP协议使用报头中的校验值来保证数据的安全。校验值首先在数据发送方通过特殊的算法计算得出,在传递到接收方之后,还需要再重新计算。如果某个数据报在传输过程中被第三方篡改或者由于线路噪音等原因受到损坏,发送和接收方的校验计算值将不会相符,由此UDP协议可以检测是否出错。这与TCP协议是不同的,后者要求必须具有校验值。 

UDPvs.TCP 

UDP和TCP协议的主要区别是两者在如何实现信息的可靠传递方面不同。TCP协议中包含了专门的传递保证机制,当数据接收方收到发送方传来的信息时,会自动向发送方发出确认消息;发送方只有在接收到该确认消息之后才继续传送其它信息,否则将一直等待直到收到确认信息为止。 

与TCP不同,UDP协议并不提供数据传送的保证机制。如果在从发送方到接收方的传递过程中出现数据报的丢失,协议本身并不能做出任何检测或提示。因此,通常人们把UDP协议称为不可靠的传输协议。 

相对于TCP协议,UDP协议的另外一个不同之处在于如何接收突法性的多个数据报。不同于TCP,UDP并不能确保数据的发送和接收顺序。例如,一个位于客户端的应用程序向服务器发出了以下4个数据报 
D1 
D22 
D333 
D4444 
但是UDP有可能按照以下顺序将所接收的数据提交到服务端的应用: 
D333 
D1 
D4444 
D22 
事实上,UDP协议的这种乱序性基本上很少出现,通常只会在网络非常拥挤的情况下才有可能发生。 
UDP协议的应用 
也许有的读者会问,既然UDP是一种不可靠的网络协议,那么还有什么使用价值或必要呢?其实不然,在有些情况下UDP协议可能会变得非常有用。因为UDP具有TCP所望尘莫及的速度优势。虽然TCP协议中植入了各种安全保障功能,但是在实际执行的过程中会占用大量的系统开销,无疑使速度受到严重的影响。反观UDP由于排除了信息可靠传递机制,将安全和排序等功能移交给上层应用来完成,极大降低了执行时间,使速度得到了保证。 

UDP协议的几个特性

(1) UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当
UDP

  UDP

它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
(2) 由于传输数据不建立连接,因此也就不需要维护连接状态,包括收发状态等,因此一台服务机可同时向多个客户机传输相同的消息。
(3) UDP信息包的标题很短,只有8个字节,相对于TCP的20个字节信息包的额外开销很小。
(4) 吞吐量不受拥挤控制算法的调节,只受应用软件生成数据的速率、传输带宽、源端和终端主机性能的限制。
(5)UDP使用尽最大努力交付,即不保证可靠交付,因此主机不需要维持复杂的链接状态表(这里面有许多参数)。
(6)UDP是面向报文的。发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层。既不拆分,也不合并,而是保留这些报文的边界,因此,应用程序需要选择合适的报文大小。 
  虽然UDP是一个不可靠的协议,但它是分发信息的一个理想协议。例如,在屏幕上报告股票市场、在屏幕上显示航空信息等等。UDP也用在路由信息协议RIP(Routing Information Protocol)中修改路由表。在这些应用场合下,如果有一个消息丢失,在几秒之后另一个新的消息就会替换它。UDP广泛用在多媒体应用中,例如,Progressive Networks公司开发的RealAudio软件,它是在因特网上把预先录制的或者现场音乐实时传送给客户机的一种软件,该软件使用的RealAudio audio-on-demand protocol协议就是运行在UDP之上的协议,大多数因特网电话软件产品也都运行在UDP之上。

一下附贴写了个UDP的收发程序基于Qt的
即可以做发送者也可以做接收者
weatherballoon.h
#ifndef WEATHERBALLOON_H
#define WEATHERBALLOON_H
#include <QWidget>
#include <QPushButton>
#include <QtNetwork/QUdpSocket>
#include <QTimer>
#include <QDateTime>
namespace Ui {
    class weatherBalloon;
}
class weatherBalloon : public QWidget
{
    Q_OBJECT
public:
    explicit weatherBalloon(QWidget *parent = 0);
    ~weatherBalloon();
private slots:
    void processPendingDatagrams();
    void sendDatagram();
private:
    Ui::weatherBalloon *ui;
    QUdpSocket udpSocket;
    QTimer timer;
    double temperature;
    double humidity;
    double altitude;
};
#endif // WEATHERBALLOON_H

main.cpp
#include <QtGui/QApplication>
#include "weatherballoon.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    weatherBalloon w;
    w.show();
    return a.exec();
}
weatherballoon.cpp
#include "weatherballoon.h"
#include "ui_weatherballoon.h"
weatherBalloon::weatherBalloon(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::weatherBalloon)
{
    udpSocket.bind(5724);//绑定端口号
    ui->setupUi(this);
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(close()));
    connect(&timer,SIGNAL(timeout()),this,SLOT(sendDatagram()));
    connect(&udpSocket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
    timer.start(2*1000);
    temperature = 10.2;
    humidity   = 5.4;
    altitude   = 100.0;
    setWindowTitle(tr("Weather Balloon"));
}
weatherBalloon::~weatherBalloon()
{
    delete ui;
}
void weatherBalloon::sendDatagram(){
    QByteArray datagram;
    QDataStream out(&datagram,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_3);
    out<<QDateTime::currentDateTime()<<temperature<<humidity<<altitude;
    qDebug()<<QDateTime::currentDateTime();
    QHostAddress address;
    address.setAddress("192.168.0.46");//发送者要把数据发送到的ip地址
    udpSocket.writeDatagram(datagram,address,5824);//发送者把数据发送的端口号,需要接受者绑定该端口号
}
void weatherBalloon::processPendingDatagrams(){
   QByteArray datagram;//拥于存放接收的数据报
   do{
       datagram.resize(udpSocket.pendingDatagramSize());//让datagram的大小为等待处理的数据报的大小,这样才能接收到完整的数据
       udpSocket.readDatagram(datagram.data(),datagram.size());//接收数据报,将其存放到datagram中
   }while(udpSocket.hasPendingDatagrams());//拥有等待的数据报
   QDateTime dateTime;
   double temperature;
   double humidity;
   double altitude;
   qDebug()<<"recive date ";
   QDataStream in(&datagram,QIODevice::ReadOnly);
   in.setVersion(QDataStream::Qt_4_3);
   in>>dateTime>>temperature>>humidity>>altitude;
   ui->dateLineEdit->setText(dateTime.date().toString());
   ui->timeLineEdit->setText(dateTime.time().toString());
   ui->temperatureLineEdit->setText(tr("%1 °c").arg(temperature));
   ui->humidityLineEdit->setText(tr("%1%").arg(humidity));
   ui->altiudeLineEdit->setText(tr("%1 m").arg(altitude));
}

一下 是接收者和发送者跟上一程序相互之间发送
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtNetwork/QUdpSocket>
#include <QTimer>
namespace Ui {
    class Dialog;
}
class Dialog : public QDialog
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
private slots:
    void processPendingDatagrams();
    void sendDatagram();
private:
    Ui::Dialog *ui;
    QUdpSocket udpSocket;
     QTimer timer;
     double temperature;
     double humidity;
     double altitude;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include <QByteArray>
#include <QDateTime>
#include <QDataStream>
Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    udpSocket.bind(5824);
    connect(&udpSocket,SIGNAL(readyRead()),this,SLOT(processPendingDatagrams()));
    ui->setupUi(this);
    timer.start(4*1000);
    temperature = 20.2;
    humidity   = 15.4;
    altitude   = 150.0;
    connect(&timer,SIGNAL(timeout()),this,SLOT(sendDatagram()));
}
Dialog::~Dialog()
{
    delete ui;
}
void Dialog::processPendingDatagrams(){
   QByteArray datagram;
   do{
       datagram.resize(udpSocket.pendingDatagramSize());
       udpSocket.readDatagram(datagram.data(),datagram.size());
   }while(udpSocket.hasPendingDatagrams());
   QDateTime dateTime;
   double temperature;
   double humidity;
   double altitude;
   QDataStream in(&datagram,QIODevice::ReadOnly);
   in.setVersion(QDataStream::Qt_4_3);
   in>>dateTime>>temperature>>humidity>>altitude;
   ui->dateLineEdit->setText(dateTime.date().toString());
   ui->timeLineEdit->setText(dateTime.time().toString());
   ui->temperatureLineEdit->setText(tr("%1 °c").arg(temperature));
   ui->humidityLineEdit->setText(tr("%1%").arg(humidity));
   ui->altiudeLineEdit->setText(tr("%1 m").arg(altitude));
}
void Dialog::sendDatagram(){
    QByteArray datagram;
    QDataStream out(&datagram,QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_3);
    out<<QDateTime::currentDateTime()<<temperature<<humidity<<altitude;
    qDebug()<<QDateTime::currentDateTime();
    QHostAddress address;
    address.setAddress("192.168.3.217");
    udpSocket.writeDatagram(datagram,address,5824);
}
main.c
#include <QtGui/QApplication>
#include "dialog.h"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();
    return a.exec();
}


以上两个程序的.pro文件添加QT += network
源码下载地址http://download.csdn.net/detail/thinkpadlove/4910515
发布了49 篇原创文章 · 获赞 30 · 访问量 19万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览