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.mzph.cn/news/695933.shtml

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

相关文章

LeetCode 0106.从中序与后序遍历序列构造二叉树:分治(递归)——五彩斑斓的题解(若不是彩色的可以点击原文链接查看)

【LetMeFly】106.从中序与后序遍历序列构造二叉树&#xff1a;分治&#xff08;递归&#xff09;——五彩斑斓的题解&#xff08;若不是彩色的可以点击原文链接查看&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/construct-binary-tree-from-inorder-an…

FSQ: FINITE SCALAR QUANTIZATION: VQ-VAE MADE SIMPLE

Paper name FINITE SCALAR QUANTIZATION: VQ-VAE MADE SIMPLE Paper Reading Note Paper URL: https://arxiv.org/abs/2309.15505 Code URL: (官方 jax 实现) https://github.com/google-research/google-research/tree/master/fsq(pytorch 实现) https://github.com/luci…

OSPF综合实验详解

一、实验要求 1&#xff0c;R4为ISP&#xff0c;其上只能配置IP地址&#xff1b;R4与其他所有直连设备间均使用公有IP&#xff1b; 2&#xff0c;R3-R5/6/7为MGRE环境&#xff0c;R3为中心站点&#xff1b; 3&#xff0c;整个OSPF环境IP基于172.16..8/16划分&#xff1b; 4…

外观设计专利的特征和特点

许多人往往将商品包装与外观设计混同起来&#xff0c;其实两者的区别很大&#xff0c;外观设计由专利法予以保护&#xff0c;简单说&#xff0c;外观设计是指工业品的外观设计&#xff0c;也就是工业品的式样&#xff0c;包括形状、图案、色彩等。下面介绍外观设计专利的特征和…

OpenWRT部署web站点并结合内网穿透实现无公网ip远程访问

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…

uniapp微信小程序-项目实战修改密码

图标是使用uview里面的图标&#xff0c;icfont也可以 以下是所有代码 <template><view><!-- 密码三个 --><view class"password" v-for"(item,index) in userList"><view class"contentuser"><view class&qu…

几个常见的C/C++语言冷知识

当涉及到C/C语言时&#xff0c;有一些冷知识可能并不为人所熟知&#xff0c;但却可以让你更深入地理解这门古老而强大的编程语言。以下是一些有趣的C/C语言冷知识。 1. 数组的下标可以是负数 在我们日常的C语言编程中&#xff0c;数组是一个非常常见的数据结构。我们习惯性地使…

DIY赴美生子必看~

现在选择赴美生子的宝妈越来越多&#xff0c;很多开始选择半DIY的形式&#xff0c;那么有哪些细节需要注意呢? 说中文的医生更方便? 这条对于DIY赴美生子者来说很关键&#xff0c;不要认为你的日常英文沟通没问题&#xff0c;涉及一些医学术语时&#xff0c;能否顺畅地与医生…

ai写作软件手机版哪个好用?

ai写作软件手机版哪个好用&#xff1f;随着技术的发展&#xff0c;越来越多的ai写作软件出现在互联网上&#xff0c;当然&#xff0c;这取决于人们对它的需求很大&#xff0c;ai写作软件可以帮助大家完成文章自动写作&#xff0c;也可以帮助大家生成优质的文案&#xff0c;同时…

提升网络质量:UDPspeeder 实现网络优化与提速

提升网络质量&#xff1a;UDPspeeder 实现网络优化与提速 背景与意义原理与功能使用方法未来展望相关链接服务 在当今高度互联的网络环境下&#xff0c;网络质量的优化和提速对于用户体验至关重要。针对高延迟和丢包率较高的网络链路&#xff0c;UDPspeeder 提供了一种前向纠错…

Shopee平台文具选品策略大揭秘:打造畅销产品,提升市场竞争力

在Shopee平台上销售文具类商品&#xff0c;是许多卖家追求的目标。然而&#xff0c;要在激烈的市场竞争中脱颖而出&#xff0c;并取得可观的销售业绩&#xff0c;需要制定一系列有效的选品策略。以下是一些在Shopee平台上进行文具选品时的关键策略&#xff0c;帮助卖家提高产品…

【杭州游戏业:创业热土,政策先行】

在前面的文章中&#xff0c;我们探讨了上海、北京、广州、深圳等城市的游戏产业现状。现在&#xff0c;我们切换视角&#xff0c;来看看另一个游戏创业热土——杭州的发展情况 最近第19届亚运会在杭州举办&#xff0c;本次亚运会上&#xff0c;电子竞技首次获准列为正式比赛项…

人脸美型SDK解决方案,包括瘦脸、大眼、瘦鼻等功能

为了满足市场不断升级的美颜需求&#xff0c;美摄科技凭借其在人脸识别与图像处理领域的深厚积累&#xff0c;推出了一款高效且易集成的人脸美型SDK解决方案。该方案旨在通过先进的算法和丰富的调节功能&#xff0c;帮助企业客户快速实现用户脸部形状的精准美化&#xff0c;进而…

一文看懂FAN73893MX 三相半桥门极驱动集成电路的选择

FAN73893MX产品概述&#xff1a; 是一款单片三相半桥栅极驱动 IC&#xff0c;设计用于高压、高速驱动 MOSFET 和 IGBT&#xff0c;工作电压高达 600 V。Fairchild 的高压工艺和共模噪声消除技术可以保证高端驱动器在高 dv/dt 噪声环境下稳定工作。先进的电平转换电路使高端栅极…

国产嵌入式教学实验箱操作教程:2-13 定时器控制实验

一、实验目的 熟悉定时器的基本结构&#xff0c;学习定时器的功能和控制方法&#xff0c;并实现基于定时器中断方式控制程序。 二、实验原理 定时器 TMS320CC6748有4个定时器/计数器&#xff0c;均可配置为64位计数器、两个独立32位计数器及自动重装32位计数器&#xff0c;…

C++笔记:OOP三大特性之继承

文章目录 一、继承的概念和定义1.1 概念1.2 定义格式1.3 继承关系和访问限定符 二、基类和派生类对象赋值兼容转换2.1 类型转换存在临时对象的意义2.2 赋值兼容转换不会产生临时变量 三、继承中的作用域四、派生类中的默认成员函数4.1 构造4.2 拷贝构造4.3 赋值重载4.4 析构 五…

C++如何避免float误差?

C如何避免float误差&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&#xff01; …

WP----Look 我看的见你,你却看不见我 tips:sql injection tips2: mysql 字符集

0x00 题目连接打开后&#xff0c;是空白的&#xff0c;源代码也是空白的 这种情况就抓包&#xff0c;看请求包和相应包里面是否有提示 相应包中存在很特别的响应头X-HT: verify 可能是参数&#xff0c;传递任意参数过去 0x01 传递5个长度的参数时&#xff0c;返回 说明参数的…

美国纽约时代广场纳斯达克大屏投放-大舍传媒

美国纽约时代广场纳斯达克大屏投放-大舍传媒 引言 对于大舍传媒来说&#xff0c;能够在美国纽约时代广场纳斯达克大屏投放广告是一个里程碑式的时刻。这不仅仅代表着大舍传媒在全球范围内的知名度与实力&#xff0c;也标志着该公司在国际市场上取得了巨大的进展。纽约时代广场…

基于docker安装HDFS

1.docker一键安装见 docker一键安装 2.拉取镜像 sudo docker pull kiwenlau/hadoop:1.03.下载启动脚本 git clone https://github.com/kiwenlau/hadoop-cluster-docker4.创建网桥 由于 Hadoop 的 master 节点需要与 slave 节点通信&#xff0c;需要在各个主机节点配置节点…