14-4_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP组播
文章目录
- 1. UDP组播的特性
- 2. UDP 组播实例程序的功能
- 3. 组播功能的程序实现
- 4. 源码
- 4.1 可视化UI设计
- 4.2 mainwindow.h
- 4.3 mainwindow.cpp
1. UDP组播的特性
下图简单表示了组播的原理。UDP 组播是主机之间“一对一组”
的通信模式,当多个客户端加入由一个组播地址定义的多播组之后,客户端向组播地址和端口发送的 UDP 数据报,组内成员都可以接收到,其功能类似于 QQ 群。
组播报文的目的地址使用 D 类 IP 地址,D 类地址不能出现在 IP 报文的源 IP 地址字段。用同一个 IP 多播地址接收多播数据报的所有主机构成了一个组,称为多播组 (或组播组)。所有的信息接收者都加入到一个组内,并且一旦加入之后,流向组地址的数据报立即开始向接收者传输,组中的所有成员都能接收到数据报。组中的成员是动态的,主机可以在任何时间加入和离开组。
所以,采用 UDP 组播必须使用一个组播地址。组播地址是 D 类IP 地址,有特定的地址段。多播组可以是永久的也可以是临时的。多播组地址中,有一部分由官方分配,称为永久多播组。永久多播组保持不变的是它的 IP 地址,组中的成员构成可以发生变化。永久多播组中成员的数量可以是任意的,甚至可以为零。那些没有保留下来的供永久多播组使用的 IP 组播地址,可以被临时多播组利用。关于组播IP 地址,有如下的一些约定:
- 224.0.0.0~224.0.0.255 为预留的组播地址 (永久组地址),地址 224.0.0.0 保留不做分配,其他地址供路由协议使用;
- 224.0.1.0~224.0.1.255 是公用组播地址,可以用于 Intermet;
- 224.0.2.0~238.255.255.255 为用户可用的组播地址 (临时组地址),全网范围内有效;
- 239.0.0.0~239.255.255.255 为本地管理组播地址,仅在特定的本地范围内有效。
所以,若是在家庭或办公室局域网内测试 UDP 组播功能,可以使用的组播地址范围是239.0.0.0~239.255.255.255。
QUdpSocket 支持 UDP 组播,joinMulticastGroup()函数使主机加入一个多播组,leaveMulticastGroup()函数使主机离开一个多播组,UDP 组播的特点是使用组播地址,其他的端口绑定、数据报收发等功能的实现与单播 UDP 完全相同。
2. UDP 组播实例程序的功能
设计一个UDP 组播实例程序 Samp14_4,在两台计算机上分别运行,进行组播通信。图 14-10是运行于主机 192.168.1.104 上的程序,图 14-11 是运行于主机 192.168.1.106 上的程序。两个主机上的程序都加入地址为239.255.43.21的多播组,绑定端口 35320进行通信。
从图 14-10 和图14-11可以看到,两个 Samp14_4 程序都可以发送和接收组播数据报,且在自已主机上发出的数据报,自己也可以接收到。
3. 组播功能的程序实现
程序的主窗口是基于 QMainWindow 的类 MainWindow,界面由 UI 设计器设计,其类定义如下(忽略 UI 设计器生成的槽函数):
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>#include <QUdpSocket>
#include <QLabel>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTprivate:QLabel *LabSocketState;QUdpSocket *udpSocket;//用于与连接的客户端通讯的QTcpSocketQHostAddress groupAddress;//组播地址QString getLocalIP();//获取本机IP地址
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:
//自定义槽函数void onSocketStateChange(QAbstractSocket::SocketState socketState);void onSocketReadyRead();//读取socket传入的数据
...private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H
其中定义了一个QHostAddress 类型变量 groupAddress,用于记录组播地址。下面是 MainWindow的构造函数的代码:
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);LabSocketState=new QLabel("Socket状态:");//LabSocketState->setMinimumWidth(200);ui->statusBar->addWidget(LabSocketState);QString localIP=getLocalIP();//本地主机名this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
//Multicast路由层次,1表示只在同一局域网内//组播TTL: 生存时间,每跨1个路由会减1,多播无法跨过大多数路由所以为1//默认值是1,表示数据包只能在本地的子网中传送。udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
// udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,ui->spinTTL->value());connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));onSocketStateChange(udpSocket->state());connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}
其中使用了 QUdpSocket::setSocketOption()函数,对 socket 进行参数设置
udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
将 socket 的 QAbstractSocket::MulticastTtlOption 值设置为1。MulticastTtlOption 是 UDP组播的数据报的生存期,数据报每跨1个路由会减1。缺省值为 1,表示多播数据报只能在同一路由下的局域网内传播。
要进行UDP 组播通信,UDP 客户端必须先加入UDP 多播组,也可以随时退出多播组。主窗口上的“加入组播”和“退出组播”按钮的代码如下:
void MainWindow::on_actStart_triggered()
{//加入组播QString IP=ui->comboIP->currentText();groupAddress=QHostAddress(IP);//多播组地址quint16 groupPort=ui->spinPort->value();//端口if (udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress))//先绑定端口{udpSocket->joinMulticastGroup(groupAddress); //加入多播组ui->plainTextEdit->appendPlainText("**加入组播成功");ui->plainTextEdit->appendPlainText("**组播地址IP:"+IP);ui->plainTextEdit->appendPlainText("**绑定端口:"+QString::number(groupPort));ui->actStart->setEnabled(false);ui->actStop->setEnabled(true);ui->comboIP->setEnabled(false);}elseui->plainTextEdit->appendPlainText("**绑定端口失败");
}void MainWindow::on_actStop_triggered()
{//退出组播udpSocket->leaveMulticastGroup(groupAddress);//退出组播udpSocket->abort(); //解除绑定ui->actStart->setEnabled(true);ui->actStop->setEnabled(false);ui->comboIP->setEnabled(true);ui->plainTextEdit->appendPlainText("**已退出组播,解除端口绑定");
}
加入组播之前,必须先绑定端口,绑定端口的语句是:
udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress)
这里指定地址为QHostAddress::AnyIPv4,端口为多播组统一的一个端口。
使用 QUdpSocket:: joinMulticastGroup()函数加入多播组,即:
udpSocket->joinMulticastGroup(groupAddress); //加入多播组
多播组地址 groupAddress 由界面上的组合框里输入。注意,局域网内的组播地址的范围239.0.0.0~239.255.255.255,绝对不能使用本机地址作为组播地址。
退出多播组,使用 QUdpSocket::leaveMulticastGroup()函数,即:
udpSocket->leaveMulticastGroup(groupAddress);//退出组播
加入多播组后,发送组播数据报也是使用 writeDatagram()函数,只是目标地址使用的是组播地址,在 readyRead()信号的槽函数里用 readDatagram()读取数据报。下面是发送和读取数据报的代码:
void MainWindow::on_btnMulticast_clicked()
{//发送组播消息quint16 groupPort=ui->spinPort->value();QString msg=ui->editMsg->text();QByteArray datagram=msg.toUtf8();udpSocket->writeDatagram(datagram,groupAddress,groupPort);
// udpSocket->writeDatagram(datagram.data(),datagram.size(),
// groupAddress,groupPort);ui->plainTextEdit->appendPlainText("[multicst] "+msg);ui->editMsg->clear();ui->editMsg->setFocus();
}void MainWindow::onSocketReadyRead()
{//读取数据报while(udpSocket->hasPendingDatagrams()){QByteArray datagram;datagram.resize(udpSocket->pendingDatagramSize());QHostAddress peerAddr;quint16 peerPort;udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);// udpSocket->readDatagram(datagram.data(),datagram.size());QString str=datagram.data();QString peer="[From "+peerAddr.toString()+":"+QString::number(peerPort)+"] ";ui->plainTextEdit->appendPlainText(peer+str);}
}
4. 源码
4.1 可视化UI设计
4.2 mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>#include <QUdpSocket>
#include <QLabel>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTprivate:QLabel *LabSocketState;QUdpSocket *udpSocket;//用于与连接的客户端通讯的QTcpSocketQHostAddress groupAddress;//组播地址QString getLocalIP();//获取本机IP地址
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:
//自定义槽函数void onSocketStateChange(QAbstractSocket::SocketState socketState);void onSocketReadyRead();//读取socket传入的数据
//void on_actStart_triggered();void on_actStop_triggered();void on_actClear_triggered();void on_actHostInfo_triggered();void on_btnMulticast_clicked();private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H
4.3 mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtNetwork>QString MainWindow::getLocalIP()
{QString hostName=QHostInfo::localHostName();//本地主机名QHostInfo hostInfo=QHostInfo::fromName(hostName);QString localIP="";QList<QHostAddress> 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;
}MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);LabSocketState=new QLabel("Socket状态:");//LabSocketState->setMinimumWidth(200);ui->statusBar->addWidget(LabSocketState);QString localIP=getLocalIP();//本地主机名this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
//Multicast路由层次,1表示只在同一局域网内//组播TTL: 生存时间,每跨1个路由会减1,多播无法跨过大多数路由所以为1//默认值是1,表示数据包只能在本地的子网中传送。udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
// udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,ui->spinTTL->value());connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));onSocketStateChange(udpSocket->state());connect(udpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}MainWindow::~MainWindow()
{udpSocket->abort();delete udpSocket;delete ui;
}void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{switch(socketState){case QAbstractSocket::UnconnectedState:LabSocketState->setText("scoket状态:UnconnectedState");break;case QAbstractSocket::HostLookupState:LabSocketState->setText("scoket状态:HostLookupState");break;case QAbstractSocket::ConnectingState:LabSocketState->setText("scoket状态:ConnectingState");break;case QAbstractSocket::ConnectedState:LabSocketState->setText("scoket状态:ConnectedState");break;case QAbstractSocket::BoundState:LabSocketState->setText("scoket状态:BoundState");break;case QAbstractSocket::ClosingState:LabSocketState->setText("scoket状态:ClosingState");break;case QAbstractSocket::ListeningState:LabSocketState->setText("scoket状态:ListeningState");}
}void MainWindow::onSocketReadyRead()
{//读取数据报while(udpSocket->hasPendingDatagrams()){QByteArray datagram;datagram.resize(udpSocket->pendingDatagramSize());QHostAddress peerAddr;quint16 peerPort;udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);// udpSocket->readDatagram(datagram.data(),datagram.size());QString str=datagram.data();QString peer="[From "+peerAddr.toString()+":"+QString::number(peerPort)+"] ";ui->plainTextEdit->appendPlainText(peer+str);}
}void MainWindow::on_actStart_triggered()
{//加入组播QString IP=ui->comboIP->currentText();groupAddress=QHostAddress(IP);//多播组地址quint16 groupPort=ui->spinPort->value();//端口if (udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress))//先绑定端口{udpSocket->joinMulticastGroup(groupAddress); //加入多播组ui->plainTextEdit->appendPlainText("**加入组播成功");ui->plainTextEdit->appendPlainText("**组播地址IP:"+IP);ui->plainTextEdit->appendPlainText("**绑定端口:"+QString::number(groupPort));ui->actStart->setEnabled(false);ui->actStop->setEnabled(true);ui->comboIP->setEnabled(false);}elseui->plainTextEdit->appendPlainText("**绑定端口失败");
}void MainWindow::on_actStop_triggered()
{//退出组播udpSocket->leaveMulticastGroup(groupAddress);//退出组播udpSocket->abort(); //解除绑定ui->actStart->setEnabled(true);ui->actStop->setEnabled(false);ui->comboIP->setEnabled(true);ui->plainTextEdit->appendPlainText("**已退出组播,解除端口绑定");
}void MainWindow::on_actClear_triggered()
{ui->plainTextEdit->clear();
}void MainWindow::on_actHostInfo_triggered()
{QString hostName=QHostInfo::localHostName();//本地主机名ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n");QHostInfo hostInfo=QHostInfo::fromName(hostName);QList<QHostAddress> 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->comboIP->findText(IP)<0)ui->comboIP->addItem(IP);}}
}void MainWindow::on_btnMulticast_clicked()
{//发送组播消息quint16 groupPort=ui->spinPort->value();QString msg=ui->editMsg->text();QByteArray datagram=msg.toUtf8();udpSocket->writeDatagram(datagram,groupAddress,groupPort);
// udpSocket->writeDatagram(datagram.data(),datagram.size(),
// groupAddress,groupPort);ui->plainTextEdit->appendPlainText("[multicst] "+msg);ui->editMsg->clear();ui->editMsg->setFocus();
}
相关文章:

14-4_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP组播
文章目录 1. UDP组播的特性2. UDP 组播实例程序的功能3. 组播功能的程序实现4. 源码4.1 可视化UI设计4.2 mainwindow.h4.3 mainwindow.cpp 1. UDP组播的特性 下图简单表示了组播的原理。UDP 组播是主机之间“一对一组”的通信模式,当多个客户端加入由一个组播地址定…...

ai图片合成软件帮你创造个性绚丽
嘿!悄悄告诉你一个小秘密,现在有一款超酷的软件,它能让你的图片变得活灵活现,就像跳出了屏幕一样!没错,这就是ai图片制作软件!想象一下,你拍摄了一张美丽的风景照片,但总…...
git 版本回退
git 没有push之前,可以用git reset --mixed回退,就是把add 的内容和commit的内容都撤销 在push之后,你只有2种操作 1.git reset 退回到你想要的那个版本 有配置选项 如果是soft就是当前版本删掉,之前改的代码保留,ha…...
使用Jackson自定义序列化操作(Jackson – Custom Serializer)
目录 Standard Serialization of an Object GraphCustom Serializer on the ObjectMapperCustom Serializer on the Class Standard Serialization of an Object Graph Data NoArgsConstructor AllArgsConstructor public class Item {public int id;public String itemName;p…...
Python-元组
元组(Tuples)详解 在Python中,元组(Tuples)是一种有序的数据类型,它可以包含任意类型的元素,包括数字、字符串、列表等。与列表相似,元组也是用来存储一组数据,但与列表…...

快速转换PDF文件: Python和PyMuPDF教程
解决问题 有时候将文档上传Claude2做分析,有大小限制,所以需要切割pdf文档为几个小点的文档,故才有了本文章。 如何用Python和PyMuPDF制作你想要大小的PDF? PDF是一种广泛使用的文件格式,可以在任何设备上查看和打印…...

规划模型Matlab代码
文章目录 数学规划定义一般形式分类 1.线性规划(linear programming)2.非线性规划(nonlinear programming)3. 整数规划(integer programming)4. 0-1规划(0-1 programming)5. 最大最小化模型6. 多目标规划模型7.敏感性分析(对权重)[例题] 数学规划定义 数…...

用html+javascript打造公文一键排版系统11:改进单一附件说明排版
一、用htmljavascript打造公文一键排版系统10中的一个bug 在 用htmljavascript打造公文一键排版系统10:单一附件说明排版 中,我们对附件说明的排版函数是: function setAtttDescFmt(p) {var t p;var a ;if (-1 ! t.indexOf(:))//是半角冒…...

snap xxx has “install-snap“ change in progress
error description * 系重复安装,进程冲突 solution 展示snap的改变 然后sudo snap abort 22即可终止该进程 之后重新运行install command~~ PS: ubuntu有时候加载不出来,执行resolvectl flush-caches,清除dns缓存…...
Elasticsearch 性能调优指南
目录 1、通用优化策略 1.1 通用最小化法则 1.2 职责单一原则 1.3 其他 2、写性能调优 2.1 基本原则 2.2 优化手段 2.2.1 增加 flush 时间间隔, 2.2.2 增加refresh_interval的参数值 2.2.3 增加Buffer大小, 2.2.4 关闭副本 2.2.5 禁用swap 2…...
学习Boost一:学习方法和学习目的
学习目的 Boost 的学习目的: 因为从知乎和CSND上根据了解内容来看,Boost作为一个历史悠久的开源库,已经脱离了一个单纯的库的概念了,他因庞大的涉及面应当被称之为库集。 并且,因为boost库优秀的试用反馈和开发人员的…...

c语言每日一练(1)
前言: 每日一练系列,每一期都包含5道选择题,2道编程题,博主会尽可能详细地进行讲解,令初学者也能听的清晰。每日一练系列会持续更新,暑假时三天之内必有一更,到了开学之后,将看学业情…...
iOS开发-CocoaLumberjack日志库实现Logger日志功能
iOS开发-Logger日志功能实现 在iOS开发中,常用CocoaLumberjack来作为日志功能实现的日志框架 一、CocoaLumberjack是什么? CocoaLumberjack 是 支持 iOS 和 Mac 平台的日志框架,使用简单,功能强大且不失灵活,它的主…...

深度学习(34)—— StarGAN(2)
深度学习(34)—— StarGAN(2) 完整项目在这里:欢迎造访 文章目录 深度学习(34)—— StarGAN(2)1. build model(1)generator(2&#…...
use lua
-- basic.lua print("hello ".."world") local a 1 --only this file can see b 2 -- global see -- not declare vaiable all asign to nil print(fuck) -- 字符串可以"" , ,[[]] -- 一些数值运算支持,进制数,科学数&a…...

网络——初识网络
网络基础 文章目录 网络基础计算机网络产生的背景认识网络协议网络协议初识协议分层OSI七层模型TCP/IP四层模型网络传输基本流程协议报头 认识IP地址认识MAC地址ifconfig查看主机地址ifconfig查看主机地址 计算机网络产生的背景 独立模式:计算机之间相互独立 早期的…...

调试技巧(2)
6. 如何写出好(易于调试)的代码 6.1 优秀的代码: 代码运行正常bug很少效率高可读性高可维护性高注释清晰文档齐全 常见的coding技巧: 使用assert尽量使用const养成良好的编码风格添加必要的注释避免编码的陷阱。 这里讲一下assert…...

骨传导耳机真不伤耳吗?骨传导耳机有什么好处?
骨传导耳机真不伤耳吗?骨传导耳机有什么好处? 我先来说说骨传导耳机的工作原理吧,骨传导是一种传声方式,声波通过颅骨、颌骨等头部骨头的振动,将声音传到内耳。其实骨传导的现象我们很常见,就像我们平时嗑瓜…...

mac切换jdk版本
查询mac已有版本 1、打开终端,输入: /usr/libexec/java_home -V注意:输入命令参数区分大小写(必须是-V) 2.目前本地装有两个版本的jdk xxxxedydeMacBook-Pro-9 ~ % /usr/libexec/java_home -V Matching Java Virtual Machines (2):20.0.1 (…...

go 基本语法(简单案例)
!注: go中 对变量申明很是严格,申明了,在没有使用的情况下,也会产生编译错误 1.行分隔符 一行就是代码,无;分割,如果需要在一行展示,需要以;分割,…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...

淘宝扭蛋机小程序系统开发:打造互动性强的购物平台
淘宝扭蛋机小程序系统的开发,旨在打造一个互动性强的购物平台,让用户在购物的同时,能够享受到更多的乐趣和惊喜。 淘宝扭蛋机小程序系统拥有丰富的互动功能。用户可以通过虚拟摇杆操作扭蛋机,实现旋转、抽拉等动作,增…...

Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...

什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...

【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...