【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"); 四、驱动管理…

最新站长工具箱源码,拥有几百个功能,安装教程

最新站长工具箱源码&#xff0c;拥有几百个功能&#xff0c;安装教程 在 Docker 上运行 docker run -e LAFREGIONCN -e APPLANGzh_CN --name my-miaoda -v ~/.miaoda-docker:/root/.miaoda -d -p 0.0.0.0:39899:39899 codegentoolbox/laftools-linux-x64:latestNOTE: 默认端…

【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…

【Python】如何在 Python 中操作 Excel

Python 操作 Excel 文件 1. 常用的几种库 xlrd和xlwt库 xlrd&#xff1a;用于读取Excel文件。xlwt&#xff1a;用于写入Excel文件。这两个库通常一起使用&#xff0c;xlrd用于读取&#xff0c;xlwt用于写入&#xff0c;但它们不支持Excel 2007及以后的.xlsx格式。 openpyxl库…

Linux的yum源安装MySQL5.7

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

【Spring Framework】Spring 事务使用的完整示例

为了详细展示 Spring 事务的使用&#xff0c;我将提供一个完整的示例&#xff0c;包括配置、代码和说明。这将涵盖以下几个方面&#xff1a; 数据库配置&#xff1a;包括数据源和事务管理器的配置。实体类&#xff1a;用于数据库操作的数据模型。DAO 层&#xff1a;数据访问对…

Android SurfaceFlinger——GraphicBuffer的提交(三十三)

在 SurfaceFlinger 中,我们 dequeueBuffer 和 queueBuffer 是 Surface 控制接口中非常重要的两个函数,分别用于从 Surface 的 BufferQueue 中取出缓冲区和向 BufferQueue 提交(队列)缓冲区。这两个函数在生产者和消费者模型中扮演着核心角色,确保了图像数据的高效和有序传…

消息队列原理题库

1. 简述什么是消息队列 &#xff1f; 消息&#xff08;Message&#xff09;是指在应用间传送的数据。消息可以非常简单&#xff0c;比如只包含文本字符串&#xff0c;也可以更复杂&#xff0c;可能包含嵌入对象。 消息队列&#xff08;Message Queue&#xff09;是一种应用间…

【算法】子集

难度:中等 题目: 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的 子集(幂集)。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1: 输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]] 示例 2: 输入…

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;可以不用。根据客户需求来 …

vue3中动态添加form表单校验

<template><div><div v-for"(formData, index) in forms" :key"index"><u-form :model"formData" :rules"rules" ref"formRefs"><u-form-item label"用户名" prop"username"…

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.…

异或和+博弈论

1.最后状态a1a2a3...an0,显然a1^a2^a3...^an0 2.对ai操作&#xff0c;变成new ai,等价于ai异或一个数字x,使得ai^xnew ai 3.因此得出结论&#xff1a;对某一堆石子(ai)的操作实际上等同于对该堆石子的异或 4.当前我的状况&#xff1a;a1^a2^a3...^an0,假设上一步,你的状况a1^a2…