[Qt网络编程]之UDP通讯的简单编程实现

这篇具有很好参考价值的文章主要介绍了[Qt网络编程]之UDP通讯的简单编程实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

hello!欢迎大家来到我的Qt学习系列之网络编程之UDP通讯的简单编程实现。希望这篇文章能对你有所帮助!!!

本篇文章的相关知识请看我的上篇文章:

目录

UDP通讯

 基于主窗口的实现

 基于线程的实现


UDP通讯

        UDP数据报协议是一个面向无连接的传输层报文协议,它简单易用,不存在 TCP协议“粘包”的问题,在强调实时、主动推送的系统中,常常用 UDP协议来实现网络双方的通信。在 Qt 中,QUdpSocket 类提供了 UDP 数据报的通信支持,下面通过两个简单的例子介绍Qt下 UDP 协议的实现。

模拟网络上经常定义的数据报文结构:

字节 1~4 5~8 9~12 13~16 17~20
定义 序号 小时 分钟 毫秒
#pragma pack(push) //保存对齐状态
#pragma pack(4) //设定为4字节对齐
struct DataStruct{
    unsigned int index;//序号
    int hour;//小时
    int minute;//分钟
    int second;//秒
    int msec;//毫秒
};
union NetBuffer{
    DataStruct data;
    char dataBuffer[20];
};
#pragma pack(pop) //恢复对齐状态

这里用了一个联合定义的数据缓冲区,便于进行数据报文的设置和解析。

需要在 *.pro 工程文件中添加 network 选项 :

QT +=core gui network

 基于主窗口的实现

        UDP报文的发送比较随意,可以在程序的任何需要的时候和位置发送 UDP报文,为了演示的简单,本例子中设置了主窗口的定时器,每秒钟发送一次报文。在接收的时候,响应接收端口 readyRead()信号,及时读取网络协议缓冲区的数值。

1.新建一个工程,在界面中添加两个列表部件,用于显示发送和接收的数据:

[Qt网络编程]之UDP通讯的简单编程实现,Qt学习,网络,tcp/ip,udp,qt,网络协议

2. 在头文件中,添加包含 QNetworkInterface、QHostAddress 和 QudpSocket 模块,添加网络数据报文的结构定义。在 MainWindow 类定义中,添加需要重载的 timerEvent 定义,添加读取数据报文操作 readPendingDatagrams 定义,以及主机地址、发送和接收 socket和缓冲区定义。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include<QMainWindow>
#include<QtNetwork/QNetworkInterface>
#include<QtNetwork/QHostAddress>
#include<QtNetwork/QUdpSocket>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

#pragma pack(push) //保存对齐状态
#pragma pack(4) //设定为4字节对齐
struct DataStruct{
    unsigned int index;//序号
    int hour;//小时
    int minute;//分钟
    int second;//秒
    int msec;//毫秒
};
union NetBuffer{
    DataStruct data;
    char dataBuffer[20];
};
#pragma pack(pop) //恢复对齐状态

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void timerEvent(QTimerEvent * event);

public slots:
    void readPendingDatagrams();
    
private:
    Ui::MainWindow *ui;
    QHostAddress hostAddress;
    QUdpSocket udpSendSocket,udpRecvSocket;
    NetBuffer sendBuffer,recvBuffer;
};
#endif // MAINWINDOW_H

3. 在 MainWindow 的构造函数中,获取本机地址,绑定发送和接收 socket,设置响应接收 socket 接收信号的槽。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //通过调用静态方法获取本机IP地址
    QList<QHostAddress> addressList = QNetworkInterface::allAddresses();
    hostAddress=addressList.at(0);
    //网络端口绑定
    udpSendSocket.bind(hostAddress,7000);
    udpRecvSocket.bind(hostAddress,7001);
    //设置定时器
    this->startTimer(1000);
    //初始化发送计数器
    sendBuffer.data.index=0;
    //建立接收 socket 的连接
    QObject::connect(&udpRecvSocket,SIGNAL(readyRead()),this,SLOT(readPendingDatagrams()));
}

4.实现发送和接收操作,并在列表中显示。发送操作是在定时器事件响应函数中实现的,上面已经设置了每秒发送一次。数据接收是在 readPendingDatagrams()函数中实现的,当接收 socket 一有数据报文包,readPendingDatagrams()就被调用,读取网络接收到的数据,并解析显示。在这里我们用了联合的方法来解析网络数据结构,方便易用。

//在 timeEvent 中设置发送数据,并在列表中显示
void MainWindow::timerEvent(QTimerEvent * event){
    QTime tm = QTime::currentTime();//获取当前时间
    sendBuffer.data.hour=tm.hour();
    sendBuffer.data.minute=tm.minute();
    sendBuffer.data.second=tm.second();
    sendBuffer.data.msec=tm.msec();
    //调用发送数据包函数,发送数据
    udpSendSocket.writeDatagram (sendBuffer.dataBuffer,sizeof(sendBuffer),hostAddress,7001);
    QString displaystring;
    displaystring=QString("Index=%1 \nTime=%2:%3:%4.%5\n")
            .arg(sendBuffer.data.index)
            .arg(sendBuffer.data.hour,2,10,QChar('0'))
            .arg(sendBuffer.data.minute,2,10,QChar('0'))
            .arg(sendBuffer.data.second,2,10,QChar('0'))
            .arg(sendBuffer.data.msec,3,10,QChar('0'));
    ui->listWidget->insertItem(0,displaystring);
    sendBuffer.data.index++;
}

//在 readPendingDatagrams 槽中,接收数据并显示
void MainWindow::readPendingDatagrams (){
    QHostAddress sender;
    quint16 senderPort;
    //调用数据接接收函数,接收数据
    udpRecvSocket.readDatagram(recvBuffer.dataBuffer,sizeof (recvBuffer),&sender,&senderPort);
    QString displaystring;
    displaystring=QString("Index=%1 \nTime=%2:%3:%4.%5\n").arg (recvBuffer.data.index)
            .arg(recvBuffer.data.hour,2,10,QChar('0'))
            .arg(recvBuffer.data.minute,2,10,QChar('0'))
            .arg(recvBuffer.data.second,2,10,QChar('0'))
            .arg(recvBuffer.data.msec,3,10,QChar('0'));
    ui->listWidget_2->insertItem(0,displaystring);
}

[Qt网络编程]之UDP通讯的简单编程实现,Qt学习,网络,tcp/ip,udp,qt,网络协议 [Qt网络编程]之UDP通讯的简单编程实现,Qt学习,网络,tcp/ip,udp,qt,网络协议


 基于线程的实现

        基于窗口部件的 UDP通信实现,虽然简单易用,但是窗口部件主要的工作是负责处理大量的用户界面信息,当有耗时的处理过程时,会影响数据的接收,造成丢帧。通常的做法是用独立的线程负责网络数据的发送和接收,再通过窗口部件显示输出,在实时系统中这种应用特别广泛。下面的例子显示的效果和前面一致,但实现的机理是完全不同的。

1.新建工程,在工程中依次新建发送和接收线程的C++文件 sendthread. h,sendthread. epp 和 reevthread. h,recvthread. cpp:

其中sendthread.h定义:

#include <QWidget>
#include<QThread>
#include<QtNetwork/QNetworkInterface>
#include<QtNetwork/QHostAddress>
#include<QtNetwork/QUdpSocket>
#include "NetBuffer.h" //就是上文定义的数据缓冲
class sendthread :public QThread
{
    Q_OBJECT
public:
    explicit sendthread(QWidget *parent=0);
protected:
    void run();
private:
    QHostAddress hostAddress;
    QUdpSocket udpsendsocket;
    NetBuffer sendBuffer;
};
#endif // SENDTHREAD_H

在 sendthread.h中定义了线程需要用到的主机地址 hostAddress、UDPsocket 端口和发送缓冲区,定义了线程需要重载的 run()操作。在 sendthread.cpp 的构造函数中,初始化参数,获取本机地址,绑定 socket 端口:

#include "sendthread.h"

sendthread::sendthread(QWidget *parent):
    QThread(parent)
{
    QList<QHostAddress> addresslist=QNetworkInterface::allAddresses();
    hostAddress=addresslist.at(0);
    udpsendsocket.bind(hostAddress,7000);
    sendBuffer.data.index=0;
}

然后重载实现 run()操作。这里要注意的是,由于主窗口的 ui变量是 protected 类型线程不能直接使用,需要线程通过主窗口的 displaySendData方法,将显示信息输出到界面中。

#include<QTime>
void sendthread::run(){
    while(true){
    QTime tm=QTime::currentTime();
    sendBuffer.data.hour=tm.hour();
    sendBuffer.data.minute =tm.minute();
    sendBuffer.data.second =tm.second();
    sendBuffer.data.msec=tm.msec();
    udpsendsocket.writeDatagram(sendBuffer.dataBuffer,sizeof(sendBuffer),hostAddress,7001);
    QString displaystring;
    displaystring=QString("Index=%1\nTime=%2:%3:%4.%5\n")
            .arg(sendBuffer.data.index)
            .arg(sendBuffer.data.hour,2,10,QChar('0'))
            .arg(sendBuffer.data.minute,2,10,QChar('0'))
            .arg(sendBuffer.data.second,2,10,QChar('0'))
            .arg(sendBuffer.data.msec,3,10,QChar('0'));
    ((MainWindow*)this->parent())->DisplaySendData(displaystring);
    sendBuffer.data.index++;
    this->sleep(1);
    }
}

其中 recvthread.h 的定义:

#include <QWidget>
#include<QThread>
#include<QtNetwork/QNetworkInterface>
#include<QtNetwork/QHostAddress>
#include<QtNetwork/QUdpSocket>
#include "NetBuffer.h"
class recvthread: public QThread
{
    Q_OBJECT
public:
    explicit recvthread(QWidget *parent=0);
protected:
    void run();
private:
    QHostAddress hostAddress;
    QUdpSocket udpRecvSocket;
    NetBuffer recvBuffer;
};

和发送线程类似,定义了主机地址 hostAddress、UDPsocket 端口和发送缓冲区,定义了需要重载的 run()操作。在构造函数中,初始化接收 socket。

recvthread::recvthread(QWidget *parent):
    QThread(parent)
{
    QList<QHostAddress> addresslist=QNetworkInterface::allAddresses();
    hostAddress=addresslist.at(0);
    udpRecvSocket.bind(hostAddress,7001);
}

在 run()中读取网络数据,并通过主窗口的 DisplayRecvData方法显示。注意这里使用了 waitForReadyRead方法以同步方式读取数据,而不是使用信号和槽的异步方法。当没有新数据到来时,线程处于挂起等待状态,当有数据到达时,立刻进入下一步处理,这种方法响应得更及时快速。

#include"mainwindow.h"
void recvthread::run(){
    while (true){
    if(udpRecvSocket.waitForReadyRead()){
        QHostAddress sender;
        quint16 senderPort;
        udpRecvSocket.readDatagram(recvBuffer.dataBuffer,sizeof(recvBuffer),&sender,&senderPort);
        QString displaystring;
        displaystring=QString("Index=%1\nTime=%2:%3:%4.%5\n")
                .arg(recvBuffer.data.index)
                .arg(recvBuffer.data.hour,2,10,QChar('0'))
                .arg(recvBuffer.data.minute,2,10,QChar('0'))
                .arg(recvBuffer.data.second,2,10,QChar('0'))
                .arg(recvBuffer.data.msec,3,10,QChar('0'));
        ((MainWindow*)this->parent())->DisplayRecvData(displaystring);
    }
}

2.在主窗口中,初始化发送和接收 socket 线程,定义 DisplaySendData 和 DisplayRecvData操作显示收发数据。

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    sendthread *sendThread=new sendthread(this);
    recvthread *recvTrhead=new recvthread(this);
    recvTrhead->start();
    sendThread->start();
}

void MainWindow::DisplaySendData(QString displaystring){
    ui->listWidget->insertItem(0,displaystring);
}

void MainWindow::DisplayRecvData(QString displaystring){
    ui->listWidget_2->insertItem(0,displaystring);
}

[Qt网络编程]之UDP通讯的简单编程实现,Qt学习,网络,tcp/ip,udp,qt,网络协议


好啦!到这里这篇文章就结束啦!这就是本篇文章的全部内容了,接下来我还是会更新一些关于Qt基础编程的相关内容的!记得点点小爱心和关注哟!!!一起共同进步,交流学习!文章来源地址https://www.toymoban.com/news/detail-857209.html

到了这里,关于[Qt网络编程]之UDP通讯的简单编程实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 网络编程套接字(二)之UDP服务器简单实现

    目录 一、服务端UdpServer 1、udp_server.hpp 1、服务器的初始化 2、服务器的运行 2、udp_server.cc 二、客户端UdpClient udp_client.cc 三、完整代码 首先,我们在该文件中,将服务器封装成一个类,而作为一款服务器,必须要有自己的端口号,同时网络服务器需要有对应的IP地址,文件描述

    2024年04月16日
    浏览(20)
  • 【网络编程】利用套接字实现一个简单的网络通信(UDP实现聊天室 附上源码)

    源IP地址(Source IP Address): 源IP地址是数据包发送方(或数据流出发点)的唯一标识符。它用于在互联网或本地网络中定位发送数据包的设备或主机。源IP地址是数据包的出发点,即数据从这个地址开始传送,向目的IP地址指示的设备发送。 在TCP/IP协议中,源IP地址通常由发

    2024年02月14日
    浏览(23)
  • 【探索Linux】P.28(网络编程套接字 —— 简单的UDP网络程序模拟实现)

    在前一篇文章中,我们详细介绍了UDP协议和TCP协议的特点以及它们之间的异同点。 本文将延续上文内容,重点讨论简单的UDP网络程序模拟实现 。通过本文的学习,读者将能够深入了解UDP协议的实际应用,并掌握如何编写简单的UDP网络程序。让我们一起深入探讨UDP网络程序的

    2024年04月08日
    浏览(59)
  • UDP数据报网络编程(实现简单的回显服务器,客户端)

           回显服务器表示客户端发的是啥,服务器就返回啥,主要是为了熟悉UDP数据报网络编程的基本步骤         对于程序的所有分析都写到了代码上 当我们用idea实现了上面的代码后可以通过idea如何开启多个客户端(一个代码开启多个客户端运行)来检验多个客户端向

    2024年02月13日
    浏览(28)
  • Qt - UDP网络编程

    UDP(User Datagram Protocol,用户数据报协议) UDP是一个轻量级、不可靠、面向数据报的、无连接的协议,多用于可靠性要求不严格,不是非常重要的传输。 QUdpSocket类继承自QAbstractSocket,用来发送和接收UDP数据报,”Socket”即套接字,套接字即IP地址+端口号。其中IP地址指定了网络

    2024年04月22日
    浏览(18)
  • Qt网络编程 (udp广播和接收例)

    使用两个项目 1 sender 用来广播\\\"hello world\\\"; 2 receiver 用来接收广播信息 1 创建Qdialog类 2 在sender.pro 中添加 QT +=network 一行代码 3 在sender.h 中声明类 class QUdpSocket; 在声明一个私有对象 QUdpSocket *sender; 4 在ui界面拖入一个按钮 用来触发广播信息 其槽函数如下 在sender.cpp 构造函数中添

    2024年02月11日
    浏览(13)
  • QT网络编程TCP/UDP开发流程 制作网络调试助手

    1、QT的网络编程: TCP和UDP TCP编程需要用到俩个类: QTcpServer 和 QTcpSocket QTcpSocket类 提供了一个TCP套接字 QTcpSocket是QAbstractSocket的一个子类,它允许您建立TCP连接和传输数据流 注意:TCP套接字不能在QIODevice::Unbuffered模式下打开。 QTcpServer类 提供一个基于tcp的服务器 2. 这个类可以接

    2023年04月08日
    浏览(18)
  • 网络编程套接字(2): 简单的UDP网络程序

    3.1 服务端创建 (1) 创建套接字 create an endpoint for communication: 创建用于通信的端点 关于socket参数详细介绍: (1) domain: 指定套接字的通信域,相当于 struct sockaddr结构体的前16比特位(2字节) domain的选项是以宏的形式给出的,我们直接选用即可。常用就是上面框住的两个: AF_UNIX,本

    2024年02月10日
    浏览(12)
  • 【Java基础教程】(四十七)网络编程篇:网络通讯概念,TCP、UDP协议,Socket与ServerSocket类使用实践与应用场景~

    了解多线程与网络编程的操作关系; 了解网络程序开发的主要模式; 了解 TCP 程序的基本实现; 在Java中,网络编程的核心意义是实现不同电脑主机之间的数据交互。Java采用了一种简化的概念,将这个过程进一步抽象为JVM(Java虚拟机)进程之间的通信。可以在同一台电脑上

    2024年02月15日
    浏览(20)
  • 【计算机网络】网络编程套接字&UDP服务器客户端的简单模拟

    需要云服务器等云产品来学习Linux的同学可以移步/–腾讯云–/官网,轻量型云服务器低至112元/年,优惠多多。(联系我有折扣哦) 每台主机都有自己的IP地址,当数据在进行通信的时候,除了要发送的数据外,在报头里面还要包含发送方的IP和接收方的IP,这里发送方的IP就

    2024年02月20日
    浏览(17)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包