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把每個消息段放在隊列中,應用程序每次從隊列中讀一個消息段。
(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
?
評論
查看更多