点击上方“Qt学视觉”,选择“星标”公众号重磅干货,第一时间送达

想要学习的同学们还请认真阅读每篇文章,相信你一定会有所收获

UDP通信概述

UDP(UserDatagramProtocol,用户数据报协议)是轻量的、不可靠的、面向数据报(datagram)、无连接的协议,它可以用于对可靠性要求不高的场合与TCP通信不同,两个程序之间进行UDP通信无 需预先建立持久的socket连接,UDP每次发送数据报都需要指定目标地址和端口(如下图所示)。

QUdpSocket类用于实现UDP通信,它从QAbstractSocket类继承,因而与QTcpSocket共享 大部分的接口函数。主要区别是QUdpSocket以数据报传输数据,而不是以连续的数据流。发送数 据报使用函数QUdpSocket::writeDatagram(),数据报的长度一般少于512字节,每个数据报包含发 送者和接收者的IP地址和端口等信息。

要进行UDP数据接收,要用QUdpSocket::bind()函数先绑定一个端口,用于接收传入的数据 报。当有数据报传入时会发射readyRead()信号,使用readDatagram()函数来读取接收到的数据报。UDP消息传送有单播、广播、组播三种模式

  • 单播(unicast)模式:一个UDP客户端发出的数据报只发送到另一个指定地址和端口的 UDP客户端,是一对一的数据传输。

  • 广播(broadcast)模式:一个UDP客户端发出的数据报,在同一网络范围内其他所有的UDP客户端都可以收到。QUdpSocket支持IPv4广播。广播经常用于实现网络发现的协议。要获取广播数据只需在数据报中指定接收端地址为QHostAddres::Broadcast, —般的广播 地址是 255.255.255.255。

  • 组播(multicast)模式:也称为多播。UDP客户端加入到另一个组播IP地址指定的多播 组,成员向组播地址发送的数据报组内成员都可以接收到,类似于QQ群的功能. QUdpSocket::joinMulticastGroup()函数实现加入多播组的功能,加入多播组后,UDP数据 的收发与正常的UDP数据收发方法一样。

使用广播和多播模式,UDP可以实现一些比较灵活的通信功能,而TCP通信只有单播模式, 没有广播和多播模式。所以,UDP通信虽然不能保证数据传输的准确性,但是具有灵活性,一般 的即时通信软件都是基于UDP通信的。

QUdpSocket类从QAbstractSocket继承而来,但是又定义了较多新的功能函数用于实现UDP 特有的一些功能,如数据报读写和多播通信功能。QUdpSocket没有定义新的信号。QUdpSocket 的主要功能函数见表

  • bool bind(quint 16 port = 0)

    • 为UDP通信绑定一个端口

  • qint64 writeDatagram(QByteArray &datagram, QHostAddress &host, quint 16 port)

    • 向目标地址和端口的UDP客户端发送数据报,返回成功 发送的字节数

  • bool hasPendingDatagrams()

    • 当至少有一个数据报需要读取时,返回true

  • qint64 pendingDatagramSize()

    • 返回第一个待读取的数据报的大小

  • qint64 readDatagram(char *data, qint64 maxSize)

    • 读取一个数据报,返回成功读取的数据报的字节数

  • bool joinMulticastGroup(QHostAddress &groupAddress)

    • 加入一个多播组

  • bool leaveMulticastGroup(QHostAddress &groupAddress)

    • 离开一个多播组

在单播、广播和多播模式下,UDP程序都是对等的,不像TCP通信那样分为客户端和服务器 端。多播和广播的实现方式基本相同,只是数据报的目标IP地址设置不同,多播模式需要加入多 播组,实现方式有较大差异。

例程如下

头文件

#pragma once#include #include "ui_QGuiUdpClient.h"#include #include class QGuiUdpClient : public QMainWindow{    Q_OBJECTpublic:    QGuiUdpClient(QWidget *parent = Q_NULLPTR);    ~QGuiUdpClient();private slots:    //自定义槽函数    void onSocketStateChange(QAbstractSocket::SocketState socketState);    void onSocketReadyRead();//读取socket传入的数据    void actStart_triggered();    void actStop_triggered();    void actHostInfo_triggered();    void actClear_triggered();    void btnSend_clicked();    void btnBroadcast_clicked();private:    Ui::QGuiUdpClient ui;private:    QLabel* m_pLabSocketState;//socket状态显示标签    QUdpSocket* m_pUdpSocket;//    QString getLocalIP();//获取本机IP地址};

源文件

#include "QGuiUdpClient.h"#include #pragma execution_character_set("utf-8")QGuiUdpClient::QGuiUdpClient(QWidget *parent)    : QMainWindow(parent){    ui.setupUi(this);    m_pLabSocketState = new QLabel("Socket状态:");//    m_pLabSocketState->setMinimumWidth(200);    ui.statusBar->addWidget(m_pLabSocketState);    QString localIP = getLocalIP();//本机IP    this->setWindowTitle(this->windowTitle() + "----本机IP:" + localIP);    ui.comboTargetIP->addItem(localIP);    m_pUdpSocket = new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket    connect(m_pUdpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),        this, SLOT(onSocketStateChange(QAbstractSocket::SocketState)));    onSocketStateChange(m_pUdpSocket->state());    connect(m_pUdpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));    connect(ui.actStart, SIGNAL(triggered()), this, SLOT(actStart_triggered()));    connect(ui.actStop, SIGNAL(triggered()), this, SLOT(actStop_triggered()));    connect(ui.actHostInfo, SIGNAL(triggered()), this, SLOT(actHostInfo_triggered()));    connect(ui.actClear, SIGNAL(triggered()), this, SLOT(actClear_triggered()));    connect(ui.btnSend, SIGNAL(clicked()), this, SLOT(btnSend_clicked()));    connect(ui.btnBroadcast, SIGNAL(clicked()), this, SLOT(btnBroadcast_clicked()));}QGuiUdpClient::~QGuiUdpClient(){    m_pUdpSocket->abort();    delete m_pUdpSocket;}void QGuiUdpClient::onSocketStateChange(QAbstractSocket::SocketState socketState){    switch (socketState)    {    case QAbstractSocket::UnconnectedState:        m_pLabSocketState->setText("scoket状态:UnconnectedState");        break;    case QAbstractSocket::HostLookupState:        m_pLabSocketState->setText("scoket状态:HostLookupState");        break;    case QAbstractSocket::ConnectingState:        m_pLabSocketState->setText("scoket状态:ConnectingState");        break;    case QAbstractSocket::ConnectedState:        m_pLabSocketState->setText("scoket状态:ConnectedState");        break;    case QAbstractSocket::BoundState:        m_pLabSocketState->setText("scoket状态:BoundState");        break;    case QAbstractSocket::ClosingState:        m_pLabSocketState->setText("scoket状态:ClosingState");        break;    case QAbstractSocket::ListeningState:        m_pLabSocketState->setText("scoket状态:ListeningState");        break;    }}void QGuiUdpClient::onSocketReadyRead(){    while (m_pUdpSocket->hasPendingDatagrams())    {        QByteArray   datagram;        datagram.resize(m_pUdpSocket->pendingDatagramSize());        QHostAddress    peerAddr;        quint16 peerPort;        m_pUdpSocket->readDatagram(datagram.data(), datagram.size(), &peerAddr, &peerPort);        QString str = datagram.data();        QString peer = "[From " + peerAddr.toString() + ":" + QString::number(peerPort) + "] ";        ui.plainTextEdit->appendPlainText(peer + str);    }}void QGuiUdpClient::actStart_triggered(){    quint16     port = ui.spinBindPort->value(); //本机UDP端口    if (m_pUdpSocket->bind(port))//绑定端口成功    {        ui.plainTextEdit->appendPlainText("**已成功绑定");        ui.plainTextEdit->appendPlainText("**绑定端口:" + QString::number(m_pUdpSocket->localPort()));        ui.actStart->setEnabled(false);        ui.actStop->setEnabled(true);    }    else        ui.plainTextEdit->appendPlainText("**绑定失败");}void QGuiUdpClient::actStop_triggered(){    m_pUdpSocket->abort(); //不能解除绑定    ui.actStart->setEnabled(true);    ui.actStop->setEnabled(false);    ui.plainTextEdit->appendPlainText("**已解除绑定");}void QGuiUdpClient::actHostInfo_triggered(){    QString hostName = QHostInfo::localHostName();//本地主机名    ui.plainTextEdit->appendPlainText("本机主机名:" + hostName + "\n");    QHostInfo   hostInfo = QHostInfo::fromName(hostName);    QList addList = hostInfo.addresses();//    if (!addList.isEmpty())    {        for (int i = 0; i < addList.count(); i++)        {            QHostAddress aHost = addList.at(i);            if (QAbstractSocket::IPv4Protocol == aHost.protocol())            {                QString IP = aHost.toString();                ui.plainTextEdit->appendPlainText("本机IP地址:" + aHost.toString());                if (ui.comboTargetIP->findText(IP) < 0)                    ui.comboTargetIP->addItem(IP);            }        }    }}void QGuiUdpClient::actClear_triggered(){    ui.plainTextEdit->clear();}void QGuiUdpClient::btnSend_clicked(){    QString     targetIP = ui.comboTargetIP->currentText(); //目标IP    QHostAddress    targetAddr(targetIP);    quint16     targetPort = ui.spinTargetPort->value();//目标port    QString  msg = ui.editMsg->text();//发送的消息内容    QByteArray  str = msg.toUtf8();    m_pUdpSocket->writeDatagram(str, targetAddr, targetPort); //发出数据报    ui.plainTextEdit->appendPlainText("[out] " + msg);    ui.editMsg->clear();    ui.editMsg->setFocus();}void QGuiUdpClient::btnBroadcast_clicked(){    quint16     targetPort = ui.spinTargetPort->value(); //目标端口    QString  msg = ui.editMsg->text();    QByteArray  str = msg.toUtf8();    m_pUdpSocket->writeDatagram(str, QHostAddress::Broadcast, targetPort);    ui.plainTextEdit->appendPlainText("[broadcast] " + msg);    ui.editMsg->clear();    ui.editMsg->setFocus();}QString QGuiUdpClient::getLocalIP(){    QString hostName = QHostInfo::localHostName();//本地主机名    QHostInfo   hostInfo = QHostInfo::fromName(hostName);    QString   localIP = "";    QList addList = hostInfo.addresses();//    if (!addList.isEmpty())    {        for (int i = 0; i < addList.count(); i++)        {            QHostAddress aHost = addList.at(i);            if (QAbstractSocket::IPv4Protocol == aHost.protocol())            {                localIP = aHost.toString();                break;            }        }    }    return localIP;}

头文件

#pragma once#include #include "ui_QGuiUdpServer.h"#include #include class QGuiUdpServer : public QMainWindow{    Q_OBJECTpublic:    QGuiUdpServer(QWidget *parent = Q_NULLPTR);    ~QGuiUdpServer();private slots:    //自定义槽函数    void onSocketStateChange(QAbstractSocket::SocketState socketState);    void onSocketReadyRead();//读取socket传入的数据    void actStart_triggered();    void actStop_triggered();    void actHostInfo_triggered();    void actClear_triggered();    void btnSend_clicked();    void btnBroadcast_clicked();private:    Ui::QGuiUdpServer ui;private:    QLabel* m_pLabSocketState;//socket状态显示标签    QUdpSocket* m_pUdpSocket;//    QString getLocalIP();//获取本机IP地址};

源文件

#include "QGuiUdpServer.h"#include #pragma execution_character_set("utf-8")QGuiUdpServer::QGuiUdpServer(QWidget *parent)    : QMainWindow(parent){    ui.setupUi(this);    m_pLabSocketState = new QLabel("Socket状态:");//    m_pLabSocketState->setMinimumWidth(200);    ui.statusBar->addWidget(m_pLabSocketState);    QString localIP = getLocalIP();//本机IP    this->setWindowTitle(this->windowTitle() + "----本机IP:" + localIP);    ui.comboTargetIP->addItem(localIP);    m_pUdpSocket = new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket    connect(m_pUdpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),        this, SLOT(onSocketStateChange(QAbstractSocket::SocketState)));    onSocketStateChange(m_pUdpSocket->state());    connect(m_pUdpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));    connect(ui.actStart, SIGNAL(triggered()), this, SLOT(actStart_triggered()));    connect(ui.actStop, SIGNAL(triggered()), this, SLOT(actStop_triggered()));    connect(ui.actHostInfo, SIGNAL(triggered()), this, SLOT(actHostInfo_triggered()));    connect(ui.actClear, SIGNAL(triggered()), this, SLOT(actClear_triggered()));    connect(ui.btnSend, SIGNAL(clicked()), this, SLOT(btnSend_clicked()));    connect(ui.btnBroadcast, SIGNAL(clicked()), this, SLOT(btnBroadcast_clicked()));}QGuiUdpServer::~QGuiUdpServer(){    m_pUdpSocket->abort();    delete m_pUdpSocket;}void QGuiUdpServer::onSocketStateChange(QAbstractSocket::SocketState socketState){    switch (socketState)    {    case QAbstractSocket::UnconnectedState:        m_pLabSocketState->setText("scoket状态:UnconnectedState");        break;    case QAbstractSocket::HostLookupState:        m_pLabSocketState->setText("scoket状态:HostLookupState");        break;    case QAbstractSocket::ConnectingState:        m_pLabSocketState->setText("scoket状态:ConnectingState");        break;    case QAbstractSocket::ConnectedState:        m_pLabSocketState->setText("scoket状态:ConnectedState");        break;    case QAbstractSocket::BoundState:        m_pLabSocketState->setText("scoket状态:BoundState");        break;    case QAbstractSocket::ClosingState:        m_pLabSocketState->setText("scoket状态:ClosingState");        break;    case QAbstractSocket::ListeningState:        m_pLabSocketState->setText("scoket状态:ListeningState");        break;    }}void QGuiUdpServer::onSocketReadyRead(){    while (m_pUdpSocket->hasPendingDatagrams())    {        QByteArray   datagram;        datagram.resize(m_pUdpSocket->pendingDatagramSize());        QHostAddress    peerAddr;        quint16 peerPort;        m_pUdpSocket->readDatagram(datagram.data(), datagram.size(), &peerAddr, &peerPort);        QString str = datagram.data();        QString peer = "[From " + peerAddr.toString() + ":" + QString::number(peerPort) + "] ";        ui.plainTextEdit->appendPlainText(peer + str);    }}void QGuiUdpServer::actStart_triggered(){    quint16     port = ui.spinBindPort->value(); //本机UDP端口    if (m_pUdpSocket->bind(port))//绑定端口成功    {        ui.plainTextEdit->appendPlainText("**已成功绑定");        ui.plainTextEdit->appendPlainText("**绑定端口:" + QString::number(m_pUdpSocket->localPort()));        ui.actStart->setEnabled(false);        ui.actStop->setEnabled(true);    }    else        ui.plainTextEdit->appendPlainText("**绑定失败");}void QGuiUdpServer::actStop_triggered(){    m_pUdpSocket->abort(); //不能解除绑定    ui.actStart->setEnabled(true);    ui.actStop->setEnabled(false);    ui.plainTextEdit->appendPlainText("**已解除绑定");}void QGuiUdpServer::actHostInfo_triggered(){    QString hostName = QHostInfo::localHostName();//本地主机名    ui.plainTextEdit->appendPlainText("本机主机名:" + hostName + "\n");    QHostInfo   hostInfo = QHostInfo::fromName(hostName);    QList addList = hostInfo.addresses();//    if (!addList.isEmpty())    {        for (int i = 0; i < addList.count(); i++)        {            QHostAddress aHost = addList.at(i);            if (QAbstractSocket::IPv4Protocol == aHost.protocol())            {                QString IP = aHost.toString();                ui.plainTextEdit->appendPlainText("本机IP地址:" + aHost.toString());                if (ui.comboTargetIP->findText(IP) < 0)                    ui.comboTargetIP->addItem(IP);            }        }    }}void QGuiUdpServer::actClear_triggered(){    ui.plainTextEdit->clear();}void QGuiUdpServer::btnSend_clicked(){    QString     targetIP = ui.comboTargetIP->currentText(); //目标IP    QHostAddress    targetAddr(targetIP);    quint16     targetPort = ui.spinTargetPort->value();//目标port    QString  msg = ui.editMsg->text();//发送的消息内容    QByteArray  str = msg.toUtf8();    m_pUdpSocket->writeDatagram(str, targetAddr, targetPort); //发出数据报    ui.plainTextEdit->appendPlainText("[out] " + msg);    ui.editMsg->clear();    ui.editMsg->setFocus();}void QGuiUdpServer::btnBroadcast_clicked(){    quint16     targetPort = ui.spinTargetPort->value(); //目标端口    QString  msg = ui.editMsg->text();    QByteArray  str = msg.toUtf8();    m_pUdpSocket->writeDatagram(str, QHostAddress::Broadcast, targetPort);    ui.plainTextEdit->appendPlainText("[broadcast] " + msg);    ui.editMsg->clear();    ui.editMsg->setFocus();}QString QGuiUdpServer::getLocalIP(){    QString hostName = QHostInfo::localHostName();//本地主机名    QHostInfo   hostInfo = QHostInfo::fromName(hostName);    QString   localIP = "";    QList addList = hostInfo.addresses();//    if (!addList.isEmpty())    {        for (int i = 0; i < addList.count(); i++)        {            QHostAddress aHost = addList.at(i);            if (QAbstractSocket::IPv4Protocol == aHost.protocol())            {                localIP = aHost.toString();                break;            }        }    }    return localIP;}

qt triggered信号_Qt之网络编程UDP通信相关推荐

  1. 网络编程 UDP通信的过程 TCP通信过程 多线程文件上传

    网络概述 协议 在网络之间传出数据时需要按照指定的标准来传输,标准中规定了数据的格式.大小.传输的方式.传输速率.形成统一规范->按照规范开发的代码->协议(应用层.传输层.网络层.链路层 ...

  2. python网络编程——UDP通信附实例参考

    简介 在网络通信编程中,用的最多的就是UDP和TCP通信了,原理这里就不分析了,网上介绍也很多,这里简单列举一下各自的优缺点和使用场景 通信方式 优点 缺点 适用场景 UDP 及时性好,快速 视网络情 ...

  3. qt tcp通信_Qt之网络编程TCP通信

    点击上方"Qt学视觉",选择"星标"公众号重磅干货,第一时间送达 想要学习的同学们还请认真阅读每篇文章,相信你一定会有所收获 TCP通信概述 TCP(Trans ...

  4. [Java网络编程]UDP通信程序练习

    代码如下: package UdpPracticePack;import java.io.BufferedReader; import java.io.IOException; import java ...

  5. 基于QT的【第一个项目】设计+所有组件配合使用+网络编程局域网通信+文件IO操作+登录界面和头像+多界面跳转+JSON数据解析+表情包制作

    基于QT的第一个项目+所有组件配合使用+网络编程局域网通信+文件IO操作+登录界面和头像+多界面跳转+JSON数据解析+表情包制作 第一阶段 网络编程局域网TCP/IP聊天QT实现 main.c ma ...

  6. c++网络编程UDP

    c++网络编程UDP 服务器端: #include<WinSock2.h> #include<iostream>#pragma comment(lib,"ws2_32 ...

  7. Java SE基础知识详解第[18]期—网络编程(通信)

    写在前面: 每一个不曾起舞的日子,都是对生命的辜负. 希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己. 以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力 ...

  8. QT入门第七天 网络编程TCP/IP/UDP+Http和JSON解析+qt事件软键盘【CSDN最详细】

    网络编程+Http和JSON解析+qt事件软键盘 第一章 QT中的网络编程 [1]涉及到的类 [2]tcp协议的流程 [2.1]服务器的流程 socket-->bind-->listen- ...

  9. Java网络编程UDP编程

    一. 简单先介绍一下网络编程 1. 概念 : 通过网络IP连接起来,实现网络通信,数据传输的操作,就是网络编程 2. 实现 : 目前来说当前主要有两种实现的方法,TCP和UDP: 其中TCP需要划分客 ...

最新文章

  1. ASP——限制表单提交时间期限简单示例
  2. Python基础七(函数)
  3. Python数模笔记-PuLP库(2)线性规划进阶
  4. js用ajax和不同页面的php互相传值的方法
  5. configure: error: cannot guess build type; you must specify one解决方法
  6. c++小程序代码_# 微信小程序的原生框架和taro对比 ##
  7. opencv舌头监测模型+keras神经网络(LeNet)
  8. C语言--------学生管理系统(源代码)
  9. 最新win7/win10/XP系统下载_「装机系统」_百度云
  10. 怎样系统的学习计算机编程,如何学习电脑编程
  11. Java 8 Nashorn 教程
  12. 百度云开发clouda学习(一)
  13. 《贝叶斯统计》最大后验密度可信集(HPD)Python实现
  14. 微信小程序的wx:for和vue的v-for
  15. Discuz被挂马的处理经验,Dz为什么会被挂马
  16. SLCP验厂辅导,发布网关是SLCP系统中用于数据托管和共享的关键角色
  17. 云服务PaaS、SaaS、IaaS
  18. 纯js实现省市区三级联动
  19. codevs 2832 6个朋友 并查集 解题报告
  20. 分享一下我收藏很久的一些代替百度的搜索引擎网站

热门文章

  1. linux定时scp脚本,linux expect 实现定时scp的任务
  2. 拼接dem,山地出现平地
  3. 【转】9、XAML名称空间详解
  4. 【转】The underlying connection was closed
  5. 【转】日邮物流:实现智慧物流,这个云上对了!
  6. 31模板方法(Template Method)
  7. (译)你应该知道的jQuery技巧
  8. JVM核心之JVM运行和类加载全过程
  9. 用姓名字段统计人数_基于 Wide amp; Deep 网络和 TextCNN 的敏感字段识别
  10. javase哪部分最难_高中物理哪部分最难?这里有答案和方法!一定要收藏