02 UDP在Qt中的实现

1.什么是UDP?

以下解释来自百度百科:https://baike.baidu.com/item/UDP

UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。UDP在IP报文的协议号是17。

UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。

与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。

2.新建一个工程

  • Projects->New Project->Application->Qt Widgets Application->Choose,见Fig2.1。
  • setNametoUDP,蓝后一路Next直到Finish,见Fig2.2。
  • 工程结构中各个文件夹放的东西:Headers--头文件、Source--源文件、Forms--界面文件,见Fig2.3。
Fig2.1 Creat a New Project

Fig2.2 Rename it to UDP

Fig2.3 My UDP Project

3.编辑界面

  • Edit\Projects\UDP\Forms下双击mainwindow.ui,进入界面设计,见图Fig3.1。
  • Display Widgets中拖两个Label过来,并依次双击将内容更改为对方的IP对方的端口,见图Fig3.2。
  • 继续在Input Widgets拉两个Line EditText Edit一个过来,在Buttons中拖两个Push Button,并按Fig3.3中调整布局和在右侧属性栏中更改各个控件的名字。
    Fig3.1 mainwindows.ui
Fig3.2 Setting the Labels
Fig3.3 Adding and Setting the Controllers

4.更改UDP.pro文件

  • Edit\UDP中双击UDP.pro
  • 将第七行QT += core gui更改为QT += core gui network,整个文件如下:
#-------------------------------------------------
#
# 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

  • 点下Fig4.1左下角的榔头,编译不运行一下。


    Fig4.1 Click Biuld Project

5.编辑mainwindow.h头文件

  • 内容如下
#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(); // 槽函数,处理信息

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);

    // 分配空间,指定父对象
    udpSocket = new QUdpSocket(this);

    // 绑定
    udpSocket->bind(8888);

    // 获取本机ip
    QString strIpAddress = QHostAddress(QHostAddress::LocalHost).toString();

    // 设置窗口的标题
    QString title = QString("服务器IP:%1,端口为:8888").arg(strIpAddress);
    setWindowTitle(title);

    // 当对方成功发送数据时
    // 自动触发 readyRead()
    connect(udpSocket, &QUdpSocket::readyRead, this, &MainWindow::dealMsg);
}

// 信息处理函数
void MainWindow::dealMsg()
{
    char buf[512] = {0};
    QHostAddress clientAddr;
    quint16 port;

    // 读取对方发送的内容
    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);

        // 设置显示内容
        ui->textEdit_Msg->setText(str);

    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

7.0给PushButton_Send增加点击响应事件

  • mainwindow.ui中对send右击选择Go to slot->clicked(),见图Fig7.1和Fig7.2
  • 自动跳转到mainwindow.cpp
  • 新增一个响应单击事件的槽函数如下:
void MainWindow::on_pushButton_Send_clicked()
{
    // 获取接受方IP
    QString ip = ui->lineEdit_IP->text();
    qint16 port = ui->lineEdit_Port->text().toInt();

    // 获取编辑区内容
    QString str = ui->textEdit_Msg->toPlainText();

    // 给指定IP发送数据
    udpSocket->writeDatagram(str.toUtf8(), QHostAddress(ip), port);
}
Fig7.1 Right Click Send
Fig7.2 Go to slot->clicked()
  • 最终的mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 分配空间,指定父对象
    udpSocket = new QUdpSocket(this);

    // 绑定
    udpSocket->bind(8888);

    // 获取本机ip
    QString strIpAddress = QHostAddress(QHostAddress::LocalHost).toString();

    // 设置窗口的标题
    QString title = QString("服务器IP:%1,端口为:8888").arg(strIpAddress);
    setWindowTitle(title);

    // 当对方成功发送数据时
    // 自动触发 readyRead()
    connect(udpSocket, &QUdpSocket::readyRead, this, &MainWindow::dealMsg);
}

// 信息处理函数
void MainWindow::dealMsg()
{
    char buf[512] = {0};
    QHostAddress clientAddr;
    quint16 port;

    // 读取对方发送的内容
    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);

        // 设置显示内容
        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();

    // 获取编辑区内容
    QString str = ui->textEdit_Msg->toPlainText();

    // 给指定IP发送数据
    udpSocket->writeDatagram(str.toUtf8(), QHostAddress(ip), port);
}

8.0测试

  • 保存一下所有文件
  • <F5>运行,见图Fig8.1
  • 在IP和端口中填入本机的也是可以收到的或者你再开一台电脑一起测试,我是直接填本机的,见图Fig8.2
  • 点击<Send>后,如图Fig8.3,证明发送成功
Fig8.1 运行效果
Fig8.2 填入参数和数据
Fig8.3 发送成功
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,635评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,628评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,971评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,986评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,006评论 6 394
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,784评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,475评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,364评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,860评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,008评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,152评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,829评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,490评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,035评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,428评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,127评论 2 356