【QT】UDP

目录

核心API

示例:回显服务器 

服务器端编写:

第一步:创建出socket对象

第二步: 连接信号槽

 第三步:绑定端口号

 第四步:编写信号槽所绑定方法

 第五步:编写第四步中处理请求的方法

客户端编写:

界面设计

代码编写

发送按钮槽函数 

处理响应函数

完整代码:

测试结果:


注意:

        使用Qt网络编程的API,需要先在 .pro文件中添加 network模块! !

QT       += core gui network

核心API

主要的类有两个  QUdpSocket 和 QNetworkDatagram,upd传输的是数据报,QNetworkDatagram就是qt中udp传输的内容;

QUdpSocket 表示⼀个 UDP 的 socket ⽂件.

名称类型说明对应原生API
bind(const QHostAddress&, quint16)
方法
绑定指定的端⼝号.
bind
receiveDatagram()
方法
返回QNetworkDatagram读取⼀个 UDP 数据报
recvfrom
writeDatagram(const QNetworkDatagram&)
方法
发送⼀个 UDP 数据报
sendto
readyRead
信号
在收到数据并准备就绪后触发
⽆ (类似于 IO 多路复⽤的通 知机制)
QNetworkDatagram 表示⼀个 UDP 数据报
名称类型说明对应原生API
QNetworkDatagram(const QByteArray&, const QHostAddress& , quint16 )
构造函
通过 QByteArray , ⽬标 IP 地址, ⽬标端⼝号 构造⼀个 UDP 数据报. 通常⽤于发送数据时.
data()
方法
获取数据报内部持有的数据. 返回
QByteArray
senderAddress()
方法
获取数据报中包含的对端的 IP 地
址.
senderPort()
方法
获取数据报中包含的对端的端⼝号.
;无

在编写udp相关代码时,注意事项:

  •  一定要先连接信号槽,再绑定端口号,一旦绑定端口了,意味着请求就可以被收到了,如果在完成绑定之后,在连接信号槽之前,有客户端把请求发过来了,此时就可能读不到这样的请求。
  •  一个端口号只能被一个socket绑定。 
  •  socket->errorString() 本质上也是对系统的errno机制进行封装

示例:回显服务器 

服务器端编写:

第一步:创建出socket对象

socket = new QUdpSocket(this);

第二步: 连接信号槽

connect(socket , &QUdpSocket::readyRead , this , &Widget::processRequest);

 第三步:绑定端口号

这里记得判断是否绑定成功,如果端口号被其他socket所绑定,我们就不能在绑定该端口号!

    bool ret = socket->bind(QHostAddress::Any,9090);

    if(!ret)

    {

        //绑定失败

        QMessageBox::critical(this,"服务器启动出错",socket->errorString());

        return;

    }

 第四步:编写信号槽所绑定方法

void Widget::processRequest()

{

    //1.读取请求并解析

    const QNetworkDatagram& requestDatagram = socket->receiveDatagram();

    QString request = requestDatagram.data(); //这里data()返回的是QByte数据

    //2.根据请求计算响应(由于这里仅仅是回显服务器,响应不需要计算,就是请求本身)

    const QString& response = process(request);

    //3.把响应写回客户端,响应数据包(数据是啥,客户端ip地址,客户端端口)

    QNetworkDatagram responseDatagram(response.toUtf8(),requestDatagram.senderAddress(),requestDatagram.senderPort());

    //response.toUtf8() 取出QString内部的字节数组

    socket->writeDatagram(responseDatagram);

    //4.把这次交互的信息,显示到界面上

    QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort())+

            "] req:" + request + ", resp:" + response;

    ui->listWidget->addItem(log);

}

 第五步:编写第四步中处理请求的方法

QString Widget::process(const QString &request)

{

    //请求处理过程,由于当前是回显服务i,响应和请求完全一样,不需要进行处理

    return request;

}

完整代码如下: 

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QNetworkDatagram>
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//创建出这个对象socket = new QUdpSocket(this);//设置窗口标题this->setWindowTitle("服务器");//连接信号槽connect(socket,&QUdpSocket::readyRead,this,&Widget::processRequest);//绑定端口号bool ret = socket->bind(QHostAddress::Any,9090);if(!ret){//绑定失败QMessageBox::critical(this,"服务器启动出错",socket->errorString());return;}}Widget::~Widget()
{delete ui;
}void Widget::processRequest()
{//1.读取请求并解析const QNetworkDatagram& requestDatagram = socket->receiveDatagram();QString request = requestDatagram.data();//2.根据请求计算响应(由于这里仅仅是回显服务器,响应不需要计算,就是请求本身)const QString& response = process(request);//3.把响应写回客户端,响应数据包(数据是啥,客户端ip地址,客户端端口)QNetworkDatagram responseDatagram(response.toUtf8(),requestDatagram.senderAddress(),requestDatagram.senderPort());//response.toUtf8() 取出QString内部的字节数组socket->writeDatagram(responseDatagram);//4.把这次交互的信息,显示到界面上QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort())+"] req:" + request + ", resp:" + response;ui->listWidget->addItem(log);
}QString Widget::process(const QString &request)
{//请求处理过程,由于当前是回显服务i,响应和请求完全一样,不需要进行处理return request;
}

客户端编写:

界面设计

我们客户端简单设计成如下:

效果如下:

端口号本质上是一个2字节的无符号整数  。

代码编写

首先我们写定义两个常量,描述服务器的地址和端口:

const QString& SERVER_IP = "127.0.0.1";
const quint16 SERVER_PORT = 9090;

发送按钮槽函数 

void Widget::on_pushButton_clicked()

{

    //1.获取输入框的内容

    const QString& text = ui->lineEdit->text();

    //2. 构造UDP请求数据,这里ip我们是QString,参数识别不出来,需要我们进行转换

    QNetworkDatagram requestDatagram(text.toUtf8(),QHostAddress(SERVER_IP),SERVER_PORT);

    //3. 发送请求数据

    socket->writeDatagram(requestDatagram);

    //4. 把发送的请求数据也添加到列表框中

    ui->listWidget->addItem("客户端说:" + text);

    //5. 把输入框的内容也清空一下,方便下次输入

    ui->lineEdit->setText("");

}

处理响应函数

void Widget::processHandle()

{

    //通过这个函数来处理收到的响应

    //1.读取到响应的数据

    const QNetworkDatagram& responseDatagram = socket->receiveDatagram();

    //这里不用换引用是因为.data()返回的是QByte类型,涉及类型转换

    QString response =responseDatagram.data();

    //2. 把响应数据显示到界面上

    ui->listWidget->addItem("服务器说:"+response);

}

完整代码:

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QUdpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void processHandle();
private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QUdpSocket* socket;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QNetworkDatagram>
const QString& SERVER_IP = "127.0.0.1";
const quint16 SERVER_PORT = 9090;
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);socket = new QUdpSocket(this);//修改窗口标题,区分这是一个客户端程序this->setWindowTitle("客户端");//通过信号槽,来处理服务器返回的数据connect(socket,&QUdpSocket::readyRead,this,&Widget::processHandle);}
Widget::~Widget()
{delete ui;
}void Widget::processHandle()
{//通过这个函数来处理收到的响应//1.读取到响应的数据const QNetworkDatagram& responseDatagram = socket->receiveDatagram();QString response =responseDatagram.data();//2. 把响应数据显示到界面上ui->listWidget->addItem("服务器说:"+response);
}void Widget::on_pushButton_clicked()
{//1.获取输入框的内容const QString& text = ui->lineEdit->text();//2. 构造UDP请求数据QNetworkDatagram requestDatagram(text.toUtf8(),QHostAddress(SERVER_IP),SERVER_PORT);//3. 发送请求数据socket->writeDatagram(requestDatagram);//4. 把发送的请求数据也添加到列表框中ui->listWidget->addItem("客户端说:" + text);//5. 把输入框的内容也清空一下,方便下次输入ui->lineEdit->setText("");
}

测试结果:

要想开启多个客户端,我们只需要找到项目对应的文件中,运行.exe文件即可 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/50571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA开发工具IDEA如何连接操作数据库

一、下载驱动 下载地址&#xff1a;【免费】mysql-connector-j-8.2.0.jar资源-CSDN文库 二、导入驱动 鼠标右击下载到IDEA中的jar包&#xff0c;选择Add as Library选项 如图就导入成功 三、加载驱动 Class.forName("com.mysql.cj.jdbc.Driver"); 四、驱动管理…

【C++】——红黑树(手撕红黑树,彻底弄懂红黑树)

目录 前言 一 红黑树简介 二 为什么需要红黑树 三 红黑树的特性 四 红黑树的操作 4.1 变色操作 4.2 旋转操作 4.3 插入操作 4.4 红黑树插入代码实现 4.5 红黑树的删除 五 红黑树迭代器实现 总结 前言 我们之前都学过ALV树&#xff0c;AVL树的本质就是一颗平…

计算机实验室排课查询小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;实验室信息管理&#xff0c;实验室预约管理&#xff0c;取消预约管理&#xff0c;实验课程管理&#xff0c;实验报告管理&#xff0c;报修信息管理&#xff0…

Linux的yum源安装MySQL5.7

linux的yum源安装MySQL5.7 一、MySQL 1、简介 MySQL 是一种流行的关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由瑞典公司 MySQL AB 开发&#xff0c;后来被 Oracle Corporation 收购。它是一个开源软件&#xff0c;提供了高效、稳定和可靠的数据管理解决…

Spring AI (三) 提示词对象Prompt

3.提示词对象Prompt 3.1.Prompt Prompt类的作用是创建结构化提示词, 实现了ModelRequest<List<Message>>接口 Prompt(String contents)&#xff1a;创建一个包含指定内容的Prompt对象。 Prompt(String contents, ChatOptions modelOptions)&#xff1a;创建一个…

某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC]

文章目录 某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现某数据泄露防护(DLP)系统NoticeAjax接口SQL注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内…

DolphinDB Web 端权限管理:可视化操作指南

在现代数据库管理中&#xff0c;高效和直观的权限管理对于用户的数据安全是至关重要的。过去 DolphinDB 用户需要依赖系统脚本来管理用户和权限&#xff0c;这对于缺乏技术背景的管理员来说既复杂又容易出错。 为了提升用户体验和操作效率&#xff0c;DolphinDB 目前在 Web 上…

数据库设计三范式

文章目录 数据库设计三范式第一范式第二范式第三范式一对一怎么设计主键共享外键唯一 一对多怎么设计多对多怎么设计 数据库设计三范式 数据库表设计的原则。教你怎么设计数据库表有效&#xff0c;并且节省空间。 如果客户有速度要求极致&#xff0c;可以不用。根据客户需求来 …

MySQL数据库练习(5)

1.建库建表 # 使用数据库 use mydb16_trigger;# 表格goods create table goods( gid char(8) primary key, name varchar(10), price decimal(8,2), num int);# 表格orders create table orders( oid int primary key auto_increment, gid char(10) not null, name varchar(10…

scrapy 爬取旅游景点相关数据(一)

第一节 Scrapy 练习爬取穷游旅游景点 配套视频可以前往B站&#xff1a;https://www.bilibili.com/video/BV1Vx4y147wQ/?vd_source4c338cd1b04806ba681778966b6fbd65 本项目为scrapy 练手项目&#xff0c;爬取的是穷游旅游景点列表数据 0 系统的环境 现在网上可以找到很多scr…

Pytorch使用教学6-张量的分割与合并

在使用PyTorch时&#xff0c;对张量的分割与合并是不可避免的操作&#xff0c;本节就带大家深刻理解张量的分割与合并。 在开始之前&#xff0c;我们先对张量的维度进行深入理解&#xff1a; t2 torch.zeros((3, 4)) # tensor([[0., 0., 0., 0.], # [0., 0., 0., 0.…

C语言边界互通传送迷宫

目录 注意事项开头程序程序的流程图程序输入与输出的效果结尾 注意事项 程序里有关字符’\033’的输出都关于Sunshine-Linux的其中一篇博客——《printf函数高级用法设置打印字体颜色和背景色等》 开头 大家好&#xff0c;我叫这是我58。今天&#xff0c;我们来看一下我用C语…

现代Java开发:使用jjwt实现JWT认证

前言 jjwt 库 是一个流行的 Java 库&#xff0c;用于创建和解析 JWT。我在学习spring security 的过程中看到了很多关于jwt的教程&#xff0c;其中最流行的就是使用jjwt实现jwt认证&#xff0c;但是教程之中依然使用的旧版的jjwt库&#xff0c;许多的类与方法已经标记弃用或者…

InsCode GPU服务器快速使用

文章目录 1. 背景介绍2. 环境配置 1. 背景介绍 InsCode服务器地址&#xff1a;https://inscode.csdn.net/workbench?tabcomputed。 2. 环境配置 新建环境后&#xff0c;按照如下步骤快速配置&#xff0c;以便后续执行深度学习模型训练。 数据 openlane 环境依赖 Copy Mini…

数据结构与算法--顺序表(Java)

&#x1f4dd;个人主页&#x1f339;&#xff1a;誓则盟约 ⏩收录专栏⏪&#xff1a;Java SE &#x1f921;往期回顾&#x1f921;&#xff1a;Java SE--基本数据类型&#xff08;详细讲解&#xff09; &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; 什么…

【Python面试题收录】Python编程基础练习题②(数据类型+文件操作+时间操作)

本文所有代码打包在Gitee仓库中https://gitee.com/wx114/Python-Interview-Questions 一、数据类型 第一题 编写一个函数&#xff0c;实现&#xff1a;先去除左右空白符&#xff0c;自动检测输入的数据类型&#xff0c;如果是整数就转换成二进制形式并返回出结果&#xff1b…

昇思25天学习打卡营第23天|CV-ResNet50迁移学习

打卡 目录 打卡 迁移学习 实战练习 数据准备 数据处理 数据处理函数 数据处理流程 数据可视化 训练模型 构建Resnet50网络 固定特征进行训练 network 的输出 训练和评估 可视化模型预测 掌握迁移学习的重点在于&#xff0c;了解你的模型结构&#xff0c;通过冻结…

数据库安全审计系统:“可视化、可控化、智能化”护航数据安全

随着政府、企事业单位的业务规模逐步扩大&#xff0c;数据库的数量明显增长&#xff0c;各数据库的访问量激增&#xff0c;数据库安全隐患也日益扩大&#xff0c;主要体现如下&#xff1a; 一是敏感信息被泄露。例如用户姓名、银行账户、联系电话、用户地址等重要信息被泄露。 …

【odoo17 | Owl】前端js钩子调用列表选择视图

概要 在我们选择多对一或者多对多字段的时候&#xff0c;经常看到可以弹出列表弹窗让人一目了然的效果&#xff0c;效果如下&#xff1a; 那么&#xff0c;这种效果是odoo本身封装好的组件&#xff0c;我们在平时的前端界面开发的时候&#xff0c;既不是后端视图的情况下&#…

【YOLOv5/v7改进系列】引入中心化特征金字塔的EVC模块

一、导言 现有的特征金字塔方法过于关注层间特征交互而忽视了层内特征的调控。尽管有些方法尝试通过注意力机制或视觉变换器来学习紧凑的层内特征表示&#xff0c;但这些方法往往忽略了对密集预测任务非常重要的被忽视的角落区域。 为了解决这个问题&#xff0c;作者提出了CF…