1.什么是UDP隶债?
以下解釋來自百度百科:https://baike.baidu.com/item/UDP
UDP 是User Datagram Protocol的簡(jiǎn)稱默赂, 中文名是用戶數(shù)據(jù)報(bào)協(xié)議旱函,是OSI(Open System Interconnection耙蔑,開放式系統(tǒng)互聯(lián)) 參考模型中一種無(wú)連接的傳輸層協(xié)議吕嘀,提供面向事務(wù)的簡(jiǎn)單不可靠信息傳送服務(wù)瑟俭,IETF RFC 768是UDP的正式規(guī)范翎卓。UDP在IP報(bào)文的協(xié)議號(hào)是17。
UDP協(xié)議全稱是用戶數(shù)據(jù)報(bào)協(xié)議摆寄,在網(wǎng)絡(luò)中它與TCP協(xié)議一樣用于處理數(shù)據(jù)包失暴,是一種無(wú)連接的協(xié)議坯门。在OSI模型中,在第四層——傳輸層逗扒,處于IP協(xié)議的上一層古戴。UDP有不提供數(shù)據(jù)包分組、組裝和不能對(duì)數(shù)據(jù)包進(jìn)行排序的缺點(diǎn)矩肩,也就是說现恼,當(dāng)報(bào)文發(fā)送之后,是無(wú)法得知其是否安全完整到達(dá)的黍檩。UDP用來支持那些需要在計(jì)算機(jī)之間傳輸數(shù)據(jù)的網(wǎng)絡(luò)應(yīng)用叉袍。包括網(wǎng)絡(luò)視頻會(huì)議系統(tǒng)在內(nèi)的眾多的客戶/服務(wù)器模式的網(wǎng)絡(luò)應(yīng)用都需要使用UDP協(xié)議。UDP協(xié)議從問世至今已經(jīng)被使用了很多年刽酱,雖然其最初的光彩已經(jīng)被一些類似協(xié)議所掩蓋喳逛,但是即使是在今天UDP仍然不失為一項(xiàng)非常實(shí)用和可行的網(wǎng)絡(luò)傳輸層協(xié)議。
與所熟知的TCP(傳輸控制協(xié)議)協(xié)議一樣棵里,UDP協(xié)議直接位于IP(網(wǎng)際協(xié)議)協(xié)議的頂層润文。根據(jù)OSI(開放系統(tǒng)互連)參考模型,UDP和TCP都屬于傳輸層協(xié)議殿怜。UDP協(xié)議的主要作用是將網(wǎng)絡(luò)數(shù)據(jù)流量壓縮成數(shù)據(jù)包的形式典蝌。一個(gè)典型的數(shù)據(jù)包就是一個(gè)二進(jìn)制數(shù)據(jù)的傳輸單位。每一個(gè)數(shù)據(jù)包的前8個(gè)字節(jié)用來包含報(bào)頭信息头谜,剩余字節(jié)則用來包含具體的傳輸數(shù)據(jù)骏掀。
2.新建一個(gè)工程
-
Projects
->New Project
->Application
->Qt Widgets Application
->Choose
,見Fig2.1乔夯。 - set
Name
toUDP
砖织,藍(lán)后一路Next
直到Finish
,見Fig2.2末荐。 - 工程結(jié)構(gòu)中各個(gè)文件夾放的東西:
Headers
--頭文件、Source
--源文件新锈、Forms
--界面文件甲脏,見Fig2.3。
3.編輯界面
- 在
Edit\Projects\UDP\Forms
下雙擊mainwindow.ui
妹笆,進(jìn)入界面設(shè)計(jì)块请,見圖Fig3.1。 - 在
Display Widgets
中拖兩個(gè)Label
過來拳缠,并依次雙擊將內(nèi)容更改為對(duì)方的IP
墩新、對(duì)方的端口
,見圖Fig3.2窟坐。 - 繼續(xù)在
Input Widgets
拉兩個(gè)Line Edit
和Text Edit
一個(gè)過來海渊,在Buttons
中拖兩個(gè)Push Button
绵疲,并按Fig3.3中調(diào)整布局和在右側(cè)屬性欄中更改各個(gè)控件的名字。
Fig3.1 mainwindows.ui
4.更改UDP.pro文件
- 在
Edit\UDP
中雙擊UDP.pro
臣疑。 - 將第七行
QT += core gui
更改為QT += core gui network
盔憨,整個(gè)文件如下:
#-------------------------------------------------
#
# Project created by QtCreator 2019-03-17T06:00:09
#
#-------------------------------------------------
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = UDP
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp
HEADERS += \
mainwindow.h
FORMS += \
mainwindow.ui
-
點(diǎn)下Fig4.1左下角的榔頭,編譯不運(yùn)行一下讯沈。
Fig4.1 Click Biuld Project
5.編輯mainwindow.h頭文件
- 內(nèi)容如下
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QUdpSocket> //UDP套接字
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void dealMsg(); // 槽函數(shù),處理信息
private:
Ui::MainWindow *ui;
QUdpSocket * udpSocket; //udp指針
};
#endif // MAINWINDOW_H
6.編輯mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 分配空間郁岩,指定父對(duì)象
udpSocket = new QUdpSocket(this);
// 綁定
udpSocket->bind(8888);
// 獲取本機(jī)ip
QString strIpAddress = QHostAddress(QHostAddress::LocalHost).toString();
// 設(shè)置窗口的標(biāo)題
QString title = QString("服務(wù)器IP:%1,端口為:8888").arg(strIpAddress);
setWindowTitle(title);
// 當(dāng)對(duì)方成功發(fā)送數(shù)據(jù)時(shí)
// 自動(dòng)觸發(fā) readyRead()
connect(udpSocket, &QUdpSocket::readyRead, this, &MainWindow::dealMsg);
}
// 信息處理函數(shù)
void MainWindow::dealMsg()
{
char buf[512] = {0};
QHostAddress clientAddr;
quint16 port;
// 讀取對(duì)方發(fā)送的內(nèi)容
qint64 len = udpSocket->readDatagram(buf, sizeof(buf), &clientAddr, &port);
if (len > 0) {
QString str = QString("[%1:%2] %3")
.arg(clientAddr.toString())
.arg(port)
.arg(buf);
// 設(shè)置顯示內(nèi)容
ui->textEdit_Msg->setText(str);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
7.0給PushButton_Send增加點(diǎn)擊響應(yīng)事件
- 在
mainwindow.ui
中對(duì)send
右擊選擇Go to slot
->clicked()
,見圖Fig7.1和Fig7.2 - 自動(dòng)跳轉(zhuǎn)到
mainwindow.cpp
- 新增一個(gè)響應(yīng)單擊事件的槽函數(shù)如下:
void MainWindow::on_pushButton_Send_clicked()
{
// 獲取接受方IP
QString ip = ui->lineEdit_IP->text();
qint16 port = ui->lineEdit_Port->text().toInt();
// 獲取編輯區(qū)內(nèi)容
QString str = ui->textEdit_Msg->toPlainText();
// 給指定IP發(fā)送數(shù)據(jù)
udpSocket->writeDatagram(str.toUtf8(), QHostAddress(ip), port);
}
- 最終的mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 分配空間,指定父對(duì)象
udpSocket = new QUdpSocket(this);
// 綁定
udpSocket->bind(8888);
// 獲取本機(jī)ip
QString strIpAddress = QHostAddress(QHostAddress::LocalHost).toString();
// 設(shè)置窗口的標(biāo)題
QString title = QString("服務(wù)器IP:%1,端口為:8888").arg(strIpAddress);
setWindowTitle(title);
// 當(dāng)對(duì)方成功發(fā)送數(shù)據(jù)時(shí)
// 自動(dòng)觸發(fā) readyRead()
connect(udpSocket, &QUdpSocket::readyRead, this, &MainWindow::dealMsg);
}
// 信息處理函數(shù)
void MainWindow::dealMsg()
{
char buf[512] = {0};
QHostAddress clientAddr;
quint16 port;
// 讀取對(duì)方發(fā)送的內(nèi)容
qint64 len = udpSocket->readDatagram(buf, sizeof(buf), &clientAddr, &port);
if (len > 0) {
QString str = QString("[%1:%2] %3")
.arg(clientAddr.toString())
.arg(port)
.arg(buf);
// 設(shè)置顯示內(nèi)容
ui->textEdit_Msg->setText(str);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_Send_clicked()
{
// 獲取接受方IP
QString ip = ui->lineEdit_IP->text();
qint16 port = ui->lineEdit_Port->text().toInt();
// 獲取編輯區(qū)內(nèi)容
QString str = ui->textEdit_Msg->toPlainText();
// 給指定IP發(fā)送數(shù)據(jù)
udpSocket->writeDatagram(str.toUtf8(), QHostAddress(ip), port);
}
8.0測(cè)試
- 保存一下所有文件
-
<F5>
運(yùn)行,見圖Fig8.1 - 在IP和端口中填入本機(jī)的也是可以收到的或者你再開一臺(tái)電腦一起測(cè)試,我是直接填本機(jī)的,見圖Fig8.2
- 點(diǎn)擊
<Send>
后,如圖Fig8.3,證明發(fā)送成功