udp协议详细介绍与qudpsocket编程

网络/协议

44人已加入

描述

  QUdpSocket

  QUdpSocket是QAbstractSocket 的子类,它们都继承了QIODevice。所以可以用QUdpSocket进行发送接收数据。它和QTcpSocket最大的区别也就是,发送数据之前不需要建立连接。

  1、UDP是一种基于无连接的、不可靠的数据报传输协议。

  2、套接字可以当作一种输入输出设备,QUdpSocket可以调用writeDatagram()和readDatagram()对套接字进行读写。每当一次数据报写入完成后会释放bytesWritten()信号。

  3、QUdpSocket在读之前要先调用bind()函数进行绑定,如果仅仅只是写的话则无需绑定。

  4、当有数据报可读时,QUdpSocket会发出readRead()信号,可以通过定义关联该信号的槽函数,对数据进行读取。此时hasPendingDatagrams()也会返回true,pendingDatagramSize()可以用于获取数据报长度,然后调用读函数进行数据的读取。

  UDP协议详解

  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协议的几个特性

  1) UDP是一个无连接协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。

  qudpsocket

  (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之上。

  以下是基于Qt的UDP的收发程序即可以做发送者也可以做接收者

  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
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分