UE4 C++联网RPC教程笔记(三)(第8~9集)完结

UE4 C++联网RPC教程笔记(三)(第8~9集)完结

  • 8. exe 后缀实现监听服务器
  • 9. C++ 实现监听服务器

8. exe 后缀实现监听服务器

前面我们通过蓝图节点实现了局域网连接的功能,实际上我们还可以给项目打包后生成的 .exe 文件创建一个快捷方式,然后修改这个快捷方式的属性中的目标就可以实现简易的联网功能。

下面内容截取自梁迪老师准备的 RPC 联网文档:

使用 .exe 后缀输入和 open IP 地址联网

注意:这里只讨论 NM_Standalone、NM_ListenServer 以及 NM_Client 的情况

  1. NM_Standalone:打包出 exe 后,不创建快捷方式直接运行 exe,执行 GetNetMode() 返回 NM_Standalone 类型,在这个状态下打印 GetWorld()->IsServer() 以及 HasAuthority() 都是 true,如果在存在监听服务器的情况下,运行命令行 open 127.0.0.1,该单独端就会链接上监听服务器,执行 GetNetMode() 返回 NM_Client 类型,打印 GetWorld()->IsServer() 以及 HasAuthority() 都是 false,如果再次运行命令行 open 127.0.0.1,该端会先断开服务器,然后再链接一次
  2. NM_ListenServer:打包出来的 exe 生成快捷方式,并且在快捷方式的属性下在 exe 结尾添加 (空格)?listen,如:RPCProject.exe ?listen,运行该快捷方式就会运行监听服务器端,执行 GetNetMode() 返回 NM_ListenServer 类型,打印 GetWorld()->IsServer() 以及 HasAuthority() 都是true,如果运行命令行 open 127.0.0.1,该监听服务器端就会变成单独端 NM_Standalone
  3. NM_Client:打包出来的 exe 生成快捷方式,并且在快捷方式的属性下在 exe 结尾添加 (空格)127.0.0.1 -game,如:RPCProject.exe 127.0.0.1 -game,运行该快捷方式,如果存在监听端,就会链接上监听服务器,成为客户端,执行 GetNetMode() 返回 NM_Client 类型,打印 GetWorld()->IsServer() 以及 HasAuthority() 都是 false

接下来我们在 GameMap 里用到的玩家控制器中添加一些打印当前端的逻辑。

RPCController.h

protected:.void EchoNetMode();

RPCController.cpp

// 引入头文件
#include "RPCHelper.h"void ARPCController::BeginPlay()
{Super::BeginPlay();// 限定打开的窗口尺寸。此处老师将变量名拼写错成 “Src”FString ScreenCommand = FString("r.setres 1280x720w");ConsoleCommand(ScreenCommand);bShowMouseCursor = false;FInputModeGameOnly InputMode;SetInputMode(InputMode);// 打印当前的端EchoNetMode();
}void ARPCController::EchoNetMode()
{ENetMode NetMode = GetNetMode();switch (NetMode){case NM_Standalone:DDH::Debug() << "NM_Standalone" << DDH::Endl();break;case NM_DedicatedServer:DDH::Debug() << "NM_DedicatedServer" << DDH::Endl();break;case NM_ListenServer:DDH::Debug() << "NM_ListenServer" << DDH::Endl();break;case NM_Client:DDH::Debug() << "NM_Client" << DDH::Endl();break;case NM_MAX:DDH::Debug() << "NM_MAX" << DDH::Endl();break;}
}

编译后,将默认关卡设置为 GameMap。随后开始打包。

在这里插入图片描述
打包成功后,运行 .exe 文件,可以看到左上角打印了当前的端名以及控制器名。

在这里插入图片描述
创建 .exe 文件的一个快捷方式,命名为 RPCCourseServer (保留 .exe 后缀),随后修改该文件的属性。

在这里插入图片描述
运行 RPCCourseServer.exe,可以看到左上角已经变成了聆听服务器。

在这里插入图片描述
再创建一个快捷方式,命名为 RPCCourseClient,这次给属性里的目标添加后缀 (空格)127.0.0.1 -game。先运行 RPCCourseServer,然后再运行 RPCCourseClient.exe,可以看到后者的窗口里左上角显示是客户端。

在这里插入图片描述
此时在服务端按下 J 键,只有在客户端能看到角色处生成了红色的数字 1。说明联网方法和变量都是可以用的。

关掉客户端,服务端左上角会显示客户端的控制器登出了。

在这里插入图片描述
保持服务端开启,运行 RPCCourse.exe,按 ~ 键(波浪符)呼出控制台,输入 open 127.0.0.1。可以看到独立端加入了服务端,并且原独立端左上角输出了当前为客户端。

在这里插入图片描述
此时在服务端按下 J 键,也是只有原独立端可以看到自己角色位置生成了一个红色的数字 1。

在服务端呼出控制台然后输入 open 127.0.0.1,服务器会关闭。

在这里插入图片描述

9. C++ 实现监听服务器

前面我们用蓝图和快捷方式实现聆听服务器联机,接下来我们尝试下用 C++ 来实现同样的效果。下面内容截取自梁迪老师准备的 RPC 联网文档:

创建寻找加入会话 C++ 模式(这里只实现局域网)

C++ 联网步骤和蓝图基本相同,但是中间多了一个 StartSession() 方法需要调用,主要可以参考

  1. UCreateSessionCallbackProxy
  2. UStartSessionCallbackProxy
  3. UFindSessionsCallbackProxy
  4. UJoinSessionCallbackProxy
  5. UDestroySessionCallbackProxy

这些类的实现,具体实现参考项目里的 URPCInstance 类。

UE4 官方推荐将联网的逻辑放在 GameInstance 下处理,GameInstance 在整个游戏所有关卡中都存在,用来传递关卡数据,在保存数据方面起作用,联网数据放在 GameInstance 下方便在任何关卡去操作联网

接下来开始实操。在默认路径下创建一个 C++ 的 Instance 类,命名为 RPCInstance

将默认地图设置成 MenuMap。

来到主界面 UI 类,声明一个 URPCInstance 的指针和相应的注册方法,用来保存对 GameInstance 的引用,并且声明两个蓝图可调用的方法用于接入主界面的按钮点击事件。

MenuWidget.h

// 提前声明
class URPCInstance;UCLASS()
class RPCCOURSE_API UMenuWidget : public UUserWidget
{GENERATED_BODY()public:void AssignRPCInstance(URPCInstance* InInstance);UFUNCTION(BlueprintCallable)void LANServerEvent();UFUNCTION(BlueprintCallable)void LANClientEvent();public:URPCInstance* RPCInstance;
};

MenuWidget.cpp

// 引入头文件
#include "RPCInstance.h"void UMenuWidget::AssignRPCInstance(URPCInstance* InInstance)
{RPCInstance = InInstance;
}void UMenuWidget::LANServerEvent()
{RPCInstance->HostSession();
}void UMenuWidget::LANClientEvent()
{RPCInstance->ClientSession();
}

RPCInstance 里承载着联网相关的逻辑,主要都是调用网络模块的 API 和利用委托绑定回调函数。

RPCInstance.h

// 引入头文件
#include "Interfaces/OnlineSessionInterface.h"	// 如果这个不行就用下面这句
//#include "../Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSessionInterface.h"	
#include "Delegates/IDelegateInstance.h"#include "RPCInstance.generated.h"// 提前声明
class IOnlineSubsystem;
class APlayerController;UCLASS()
class RPCCOURSE_API URPCInstance : public UGameInstance
{GENERATED_BODY()public:URPCInstance();// 注册玩家控制器,并且获取联网系统和端 IDvoid AssignPlayerController(APlayerController* InController);// 创建会话void HostSession();// 寻找会话void ClientSession();// 销毁会话void DestroySession();protected:// 开启服务器回调函数void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful);void OnStartOnlineGameComplete(FName SessionName, bool bWasSuccessful);// 加入服务器回调函数void OnFindSessionsComplete(bool bWasSuccessful);void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);// 销毁会话回调函数void OnDestroySessionComplete(FName SessionName, bool bWAsSuccessful);protected:APlayerController* PlayerController;// 开启服务器委托与句柄FOnCreateSessionCompleteDelegate OnCreateSessionCompleteDelegate;FOnStartSessionCompleteDelegate OnStartSessionCompleteDelegate;FDelegateHandle OnCreateSessionCompleteDelegateHandle;FDelegateHandle OnStartSessionCompleteDelegateHandle;// 加入服务器委托与句柄FOnFindSessionsCompleteDelegate OnFindSessionsCompleteDelegate;FOnJoinSessionCompleteDelegate OnJoinSessionCompleteDelegate;FDelegateHandle OnFindSessionsCompleteDelegateHandle;FDelegateHandle OnJoinSessionCompleteDelegateHandle;// 销毁会话委托与句柄FOnDestroySessionCompleteDelegate OnDestroySessionCompleteDelegate;FDelegateHandle OnDestroySessionCompleteDelegateHandle;// 联网系统IOnlineSubsystem* OnlineSub;// 端的 IDTSharedPtr<const FUniqueNetId> UserID;// 保存寻找到的 SessionsTSharedPtr<FOnlineSessionSearch> SearchObject;
};

RPCInstance.cpp

// 引入头文件
#include "../Plugins/Online/OnlineSubsystem/Source/Public/OnlineSubsystem.h"
#include "../Plugins/Online/OnlineSubsystem/Source/Public/OnlineSessionSettings.h"
#include "../Plugins/Online/OnlineSubsystem/Source/Public/Interfaces/OnlineSessionInterface.h"
#include "../Plugins/Online/OnlineSubsystemUtils/Source/OnlineSubsystemUtils/Public/OnlineSubsystemUtils.h"
#include "GameFramework/PlayerController.h"
#include "RPCHelper.h"
#include "Kismet/GameplayStatics.h"URPCInstance::URPCInstance()
{// 绑定回调函数OnCreateSessionCompleteDelegate = FOnCreateSessionCompleteDelegate::CreateUObject(this, &URPCInstance::OnCreateSessionComplete);OnStartSessionCompleteDelegate = FOnStartSessionCompleteDelegate::CreateUObject(this, &URPCInstance::OnStartOnlineGameComplete);OnFindSessionsCompleteDelegate = FOnFindSessionsCompleteDelegate::CreateUObject(this, &URPCInstance::OnFindSessionsComplete);OnJoinSessionCompleteDelegate = FOnJoinSessionCompleteDelegate::CreateUObject(this, &URPCInstance::OnJoinSessionComplete);OnDestroySessionCompleteDelegate = FOnDestroySessionCompleteDelegate::CreateUObject(this, &URPCInstance::OnDestroySessionComplete);
}void URPCInstance::AssignPlayerController(APlayerController* InController)
{PlayerController = InController;// 获取 OnlineSub// 获取方式一:Online::GetSubsystem(GetWorld(), NAME_None),推荐方式// 获取方式二:使用 IOnlineSubsystem::Get(),直接获取可以 CreateSession 但是 JoinSession 后客户端没有跳转场景OnlineSub = Online::GetSubsystem(PlayerController->GetWorld(), NAME_None);// 获取 UserID// 获取方式一:UGameplayStatics::GetGameInstance(GetWorld())->GetLocalPlayers()[0]->GetPreferredUniqueNetId()if (GetLocalPlayers().Num() == 0) {DDH::Debug() << "No LocalPlayer Exists, Can't Get UserID" << DDH::Endl();}else {UserID = (*GetLocalPlayers()[0]->GetPreferredUniqueNetId()).AsShared();}#if 0// 获取方式二:使用 PlayerState 获取,该方式在打包成 exe 运行无问题,但是在编辑器模式下运行多个窗口,就会找不到 PlayerStateif (PlayerController->PlayerState)UserID = PlayerController->PlayerState->UniqueId.GetUniqueNetId();elseDDH::Debug() << "No PlayerState Exists, Can't Get UserID" << DDH::Endl();
#endif// 如果在这里直接获取 Session 运行时会报错,生命周期的问题
}void URPCInstance::HostSession()
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 会话设置FOnlineSessionSettings Settings;// 连接数Settings.NumPublicConnections = 10;Settings.bShouldAdvertise = true;Settings.bAllowJoinInProgress = true;// 使用局域网Settings.bIsLANMatch = true;Settings.bUsesPresence = true;Settings.bAllowJoinViaPresence = true;// 绑定委托OnCreateSessionCompleteDelegateHandle = Session->AddOnCreateSessionCompleteDelegate_Handle(OnCreateSessionCompleteDelegate);// 创建会话Session->CreateSession(*UserID, NAME_GameSession, Settings);}}
}void URPCInstance::ClientSession()
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 实例化搜索结果指针并且设定参数SearchObject = MakeShareable(new FOnlineSessionSearch);// 返回结果数SearchObject->MaxSearchResults = 10;// 是否是局域网,就是 IsLANSearchObject->bIsLanQuery = true;SearchObject->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);// 绑定寻找会话委托OnFindSessionsCompleteDelegateHandle = Session->AddOnFindSessionsCompleteDelegate_Handle(OnFindSessionsCompleteDelegate);// 进行会话寻找Session->FindSessions(*UserID, SearchObject.ToSharedRef());}}
}void URPCInstance::DestroySession()
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 绑定销毁会话委托OnDestroySessionCompleteDelegateHandle = Session->AddOnDestroySessionCompleteDelegate_Handle(OnDestroySessionCompleteDelegate);// 执行销毁会话Session->DestroySession(NAME_GameSession);}}
}void URPCInstance::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful)
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 解绑创建会话完成回调函数Session->ClearOnCreateSessionCompleteDelegate_Handle(OnCreateSessionCompleteDelegateHandle);// 判断创建会话是否成功if (bWasSuccessful) {DDH::Debug() << "CreateSession Succeed" << DDH::Endl();// 绑定开启会话委托OnStartSessionCompleteDelegateHandle = Session->AddOnStartSessionCompleteDelegate_Handle(OnStartSessionCompleteDelegate);// 执行开启会话Session->StartSession(NAME_GameSession);}elseDDH::Debug() << "CreateSession Failed" << DDH::Endl();}}
}void URPCInstance::OnStartOnlineGameComplete(FName SessionName, bool bWasSuccessful)
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 注销开启会话委托绑定Session->ClearOnStartSessionCompleteDelegate_Handle(OnStartSessionCompleteDelegateHandle);if (bWasSuccessful) {DDH::Debug() << "StartSession Succeed" << DDH::Endl();// 服务端跳转场景UGameplayStatics::OpenLevel(PlayerController->GetWorld(), FName("GameMap"), true, FString("listen"));}elseDDH::Debug() << "StartSession Failed" << DDH::Endl();}}
}void URPCInstance::OnFindSessionsComplete(bool bWasSuccessful)
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 取消寻找会话委托绑定Session->ClearOnStartSessionCompleteDelegate_Handle(OnStartSessionCompleteDelegateHandle);if (bWasSuccessful) {// 如果收集的结果存在并且大于 1if (SearchObject.IsValid() && SearchObject->SearchResults.Num() > 0) {DDH::Debug() << "Find Sessions Succeed" << DDH::Endl();// 绑定加入 Session 委托OnJoinSessionCompleteDelegateHandle = Session->AddOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegate);// 执行加入 SessionSession->JoinSession(*UserID, NAME_GameSession, SearchObject->SearchResults[0]);}elseDDH::Debug() << "Find Sessions Succeed But Num == 0" << DDH::Endl();}elseDDH::Debug() << "Find Sessions Failed" << DDH::Endl();}}
}void URPCInstance::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result)
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 取消加入会话委托绑定Session->ClearOnJoinSessionCompleteDelegate_Handle(OnJoinSessionCompleteDelegateHandle);// 如果加入成功if (Result == EOnJoinSessionCompleteResult::Success) {// 传送玩家到新地图FString ConnectString;if (Session->GetResolvedConnectString(NAME_GameSession, ConnectString)) {DDH::Debug() << "Join Sessions Succeed" << DDH::Endl();// 客户端切换到服务器的关卡PlayerController->ClientTravel(ConnectString, TRAVEL_Absolute);}}else DDH::Debug() << "Join Sessions Failed" << DDH::Endl();}}
}void URPCInstance::OnDestroySessionComplete(FName SessionName, bool bWAsSuccessful)
{if (OnlineSub) {IOnlineSessionPtr Session = OnlineSub->GetSessionInterface();if (Session.IsValid()) {// 注销销毁会话委托Session->ClearOnDestroySessionCompleteDelegate_Handle(OnDestroySessionCompleteDelegateHandle);// 其他逻辑...}}
}

读者可能会发现上面的代码中,绑定委托后直接就通过 Session 执行相应逻辑了,然后在接下来的逻辑里解绑委托。这里笔者倾向于将这一过程理解为 装弹 —> 发射 —> 退弹壳。UE4 已经将网络模块的细枝末节都为我们封装好了,我们只需要知道如何使用就够了,当然,喜欢探索的读者也可以查阅源码去深入理解。

在主界面控制器里注册自己到 RPCInstance,并且将 RPCInstance 注册到主界面 UI。

MenuController.cpp

// 引入头文件
#include "Kismet/GameplayStatics.h"
#include "RPCInstance.h"void AMenuController::BeginPlay()
{// 获取 GameInstanceURPCInstance* RPCInstance = Cast<URPCInstance>(UGameplayStatics::GetGameInstance(GetWorld()));RPCInstance->AssignPlayerController(this);UClass* MenuWidgetClass = LoadClass<UMenuWidget>(NULL, TEXT("WidgetBlueprint'/Game/Blueprint/MenuWidget_BP.MenuWidget_BP_C'"));UMenuWidget* MenuWidget = CreateWidget<UMenuWidget>(GetWorld(), MenuWidgetClass);MenuWidget->AddToViewport();MenuWidget->AssignRPCInstance(RPCInstance);	// 注册 RPCInstance 到 MenuWidget
}

最后添加一些网络模块相关的依赖。

RPCCourse.Build.cs

public RPCCourse(ReadOnlyTargetRules Target) : base(Target){PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "Slate", "UMG", "HeadMountedDisplay", "OnlineSubsystem", "OnlineSubsystemUtils" });	// 添加这三个模块依赖// 添加动态加载模组DynamicallyLoadedModuleNames.AddRange(new string[] {"OnlineSubsystemNull",});}

编译后,在项目设置里将默认的 GameInstance 设置为 RPCInstance。

来到 MenuWidget_BP 的图表,重新调整两个按钮点击事件的连接节点如下:

在这里插入图片描述
此时运行玩家数应该是 3。运行后,在服务端创建服务器,创建成功;让另外两个客户端加入服务器,也能进入成功。并且在服务端按 J 键,另外两个客户端各自能看到自己角色处生成红色数字。

不过如果在客户端创建服务器,另外一个客户端可以加入,但是服务端加入会显示找到会话和加入成功,但不会跳转到 GameMap。所以必须要让服务端创建服务器才能正常运作。

至此,梁迪老师的 RPC 课程到这里就结束了,衷心感谢梁迪老师提供的优质课程 : )

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

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

相关文章

【力扣hot100】刷题笔记Day10

前言 一鼓作气把链表给刷完&#xff01;&#xff01;中等题困难题冲冲冲啊啊啊&#xff01; 25. K 个一组翻转链表 - 力扣&#xff08;LeetCode&#xff09; 模拟 class Solution:def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:# 翻转…

C语言中的字体背景颜色汇总

客官请看效果 客官请看代码 #include <stdio.h> #include <stdlib.h> #include <windows.h>int main() {int i;for (i 0; i < 254; i) {SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), i); // 设置当前文本颜色为循环变量对应的颜色printf(…

如何使用移动端设备在公网环境远程访问本地黑群晖

文章目录 前言本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是前排提醒&#xff1a; 1. 搭建群晖虚拟机1.1 下载黑群晖文件vmvare虚拟机安装包1.2 安装VMware虚拟机&#xff1a;1.3 解压黑群晖虚拟机文件1.4 虚拟机初始化1.5 没有搜索到黑群晖的解…

LabVIEW燃料电池船舶电力推进监控系统

LabVIEW燃料电池船舶电力推进监控系统 随着全球经济一体化的推进&#xff0c;航运业的发展显得尤为重要&#xff0c;大约80%的世界贸易依靠海上运输实现。传统的船舶推进系统主要依赖于柴油机&#xff0c;这不仅耗能高&#xff0c;而且排放严重&#xff0c;对资源和环境的影响…

128 Linux 系统编程6 ,C++程序在linux 上的调试,GDB调试

今天来整理 GDB 调试。 在windows 上我们使用vs2017开发&#xff0c;可以手动的加断点&#xff0c;debug。 那么在linux上怎么加断点&#xff0c;debug呢&#xff1f;这就是今天要整理的GDB调试工具了。 那么有些同学可能会想到&#xff1a;我们在windows上开发&#xff0c;…

《高质量的C/C++编程规范》学习

目录 一、编程规范基础知识 1、头文件 2、程序的板式风格 3、命名规则 二、表达式和基本语句 1、运算符的优先级 2、复合表达式 3、if语句 4、循环语句的效率 5、for循环语句 6、switch语句 三、常量 1、#define和const比较 2、常量定义规则 四、函数设计 1、参…

python input 输入

input()函数包含四个方面&#xff1a;input()函数的使用/结果的赋值/数据类型/结果的强制转换。是实现人机互动沟通的关键&#xff0c;需要在终端出输入信息。我们可以把input()函数当作一扇链接现实世界与代码世界的门&#xff0c; 如下图 先看一个例子&#xff1a;  运行后终…

Spring Framework

Spring Framework Spring 是一款开源的轻量级 Java 开发框架&#xff0c;旨在提高开发人员的开发效率以及系统的可维护性。 Spring 框架指的都是 Spring Framework&#xff0c;它是很多模块的集合&#xff0c;如下图所示&#xff1a; 一、Core Container Spring 框架的核心模…

【算法 - 动态规划】最长回文子序列

上篇文章中&#xff0c;我们学习一个新的模型&#xff1a; 样本对应模型&#xff0c;该模型的套路就是&#xff1a;以结尾位置为出发点&#xff0c;思考两个样本的结尾都会产生哪些可能性 。 而前篇文章中的 纸牌博弈问题 属于 [L , R]上范围尝试模型。该模型给定一个范围&…

跨境电商版权争端,商家或在SHEIN的强势中迷茫?

在跨境商家眼里&#xff0c;欧美市场的“红线”是什么&#xff1f; 答案肯定有侵权。侵权的后果&#xff0c;轻则产品下架&#xff0c;重则封店吃官司&#xff0c;成熟市场对知识产权的重视&#xff0c;本质上也是在维护原创商家。因此&#xff0c;在不少与设计有关的行业&…

【统计分析数学模型】聚类分析: 系统聚类法

【统计分析数学模型】聚类分析&#xff1a; 系统聚类法 一、聚类分析1. 基本原理2. 距离的度量&#xff08;1&#xff09;变量的测量尺度&#xff08;2&#xff09;距离&#xff08;3&#xff09;R语言计算距离 三、聚类方法1. 系统聚类法2. K均值法 三、示例1. Q型聚类&#x…

【算法与数据结构】链表、哈希表、栈和队列、二叉树(笔记二)

文章目录 四、链表理论五、哈希表理论五、栈和队列理论5.1 单调栈 六、二叉树理论6.1 树的定义6.2 二叉树的存储方式6.3 二叉树的遍历方式6.4 高度和深度 最近博主学习了算法与数据结构的一些视频&#xff0c;在这个文章做一些笔记和心得&#xff0c;本篇文章就写了一些基础算法…

Python 读取创建word文档

本篇文章内容为使用python 读取word文档和创建word文档 读取doc文件 引入类库 示例如下&#xff1a; import win32com import win32com.client import os 读取doc文件 通过得到的doc文件路径调用系统word功能。 打开文件获取其中的文本信息&#xff0c;输出文本信息&#…

vue+nodejs+uniapp婚纱定制婚庆摄影系统 微信小程序 springboot+python

目前移动互联网大行其道&#xff0c;人人都手中拿着智能机&#xff0c;手机手机&#xff0c;手不离机&#xff0c;如果开发一个用在手机上的程序软件&#xff0c;那是多么的符合潮流&#xff0c;符合管理者和客户的理想。本次就是开发婚庆摄影小程序&#xff0c;有管理员&#…

pclpy Ransac平面分割算法输出的索引从点云中提取点云的子集

pclpy Ransac平面分割算法输出的索引从点云中提取点云的子集 一、算法原理二、代码三、结果1.sor统计滤波2.Ransac内点分割平面3.Ransac外点分割平面 四、相关数据 一、算法原理 1、Ransac介绍 RANSAC(RAndom SAmple Consensus,随机采样一致)算法是从一组含有“外点”(outlier…

docker运行onlyoffice,并配置https访问【参考仅用】

官方说明&#xff1a; Installing ONLYOFFICE Docs for Docker on a local server - ONLYOFFICEhttps://helpcenter.onlyoffice.com/installation/docs-developer-install-docker.aspx 一、容器端口、目录卷映射 sudo docker run --name容器名称 --restartalways -i -t -d -p…

论文精读--GPT1

把transformer的解码器拿出来&#xff0c;在没有标号的大量文本数据上训练一个语言模型&#xff0c;来获得预训练模型&#xff0c;然后到子任务上微调&#xff0c;得到每个任务所需的分类器 Abstract Natural language understanding comprises a wide range of diverse tasks…

高通XBL阶段读取分区

【需求】&#xff1a; 在某些场景下&#xff0c;需要在XBL阶段读取分区数据&#xff0c;需要验证xbl阶段方案 这里主要以裸分区为例&#xff0c;比如oem分区。 1、创建一个1MB大小的oem.img&#xff0c;写入内容“test oem partition” 创建方式&#xff1a; dd if/dev/null …

独立版表情包小程序完整版源码前后端源码,附带系统搭建教程

搭建要求&#xff1a; 1.系统要求Nginx 1.18.0PHP-7.2mysql5.6&#xff0c;开启 ssl&#xff0c;php需要安装 sg11 扩展 2.设置伪静态 location / { index index.php index.html index.htm; if (!-e $request_filename) { rewrite ^/(.*)$ /index.php?s$1; } } location /a…

计算机体系架构初步入门

&#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09;开发基础教程 &#x1f380;CSDN主页 发狂的小花 &#x1f304;人生秘诀&#xff1a;学习的本质就是极致重复! 目录 1 计算机五大…