ue4 异步加载关卡_UE4 网络相关之网络连接的建立UPendingNetGame

本文详细探讨了UE4客户端如何通过UPendingNetGame与服务器建立网络连接,从NMT_Hello开始,经过NMT_Challenge、NMT_Login、NMT_Welcome,最终完成NMT_Join过程,涉及网络驱动、连接验证和关卡加载等关键步骤。
摘要由CSDN通过智能技术生成

前言

  • UE4版本4.25

孤傲雕:UE4 网络相关之网络驱动器(UNetDriver)的顺藤摸瓜
接前文, 在扒了一大堆代码之后, 对网络连接最开始的地方, 有了一定的了解.

  • 服务器什么时候创建UNetDriver开始监听端口, 支持客户端连接.
  • 客户端什么时候创建UPendingNetGame开始连接服务器.


下一步, 自然是进一步深扒, 客户端是如何和服务器建立连接, 直到两边可以发送RPC事件和进行属性同步为止.


客户端开始向服务器进行请求, 尝试创建连接, 主要处理在UPendingNetGame类中

38f4610352098b5c566ec651b1d9a2cf.png
  1. 创建UPendingNetGame, 通过NewObject创建对应对象, 构造函数无处理, 略

c5bdd8e89acd379b4a50fc9accf5fbf5.png

2. 调用UPendingNetGame::Initialize初始化函数, 传入FURL信息

这个信息包含了服务器地址、端口、地图信息、连接参数等内容.

2aeb43dcb96b61e8a863a1801bdd7791.png

3. 调用UPendingNetGame::InitNetDriver, 开始初始化网络驱动

ddcdbd06787c2bdfaacd29c7ed0eb265.png

d6f3002ca172c3f4f3d972362a99c2dd.png

先看上图这个全局变量GDisallowNetworkTravel, 如果为true, 则禁止任何网络连接切换, 在处理切换关卡时拒绝这一请求.

此处客户端与服务器的连接处理与该值对应, 如果不处理, 直接连接错误, 记录日志

0965f21d05437a66c5dfecafc7856617.png

然后, 扫一眼, 明显分为创建UNetDriver网络驱动初始化两部分

b2fbf735db43933eba8a78f8c9a6a473.png

创建初始化UNetDriver相关, 此处不做扩展, 见其他文章

14f180dc30b9209d70eb3ee3fb153830.png

如图广播FNetDelegates::OnPendingNetGameConnectionCreated

af179d61c5a34b603f7ce8c05586e9e6.png

9ed325e3146cc1b29e9b6fad32ecfe07.png

如果NetDriver中的ServerConnectionPacketHander存在, 会先调用PacketHandlerBeginHandshaking建立连接, 完成后调用SendInitialJoin.

不存在, 则直接创建.

在做了这么多准备工作(见其他文章)后.

这个时候, 和服务器一个沟通的渠道就建立完成了, 接下来就开始和服务器友好的"沟通"一下.


第一回合 NMT_Hello

eb361bfdd0facbb0d9e7e1861705536a.png

客户端先向服务器友好礼貌打一声招呼!

Hello!

47f3fd68c077769e309974da8716c5d1.png

服务器收到这一NMT_Hello消息

UWorld::Tick函数的多播转交到UNetDriver

UNetDriver再转交给与客户端对应的UNetConnection, 并进一步处理

最后, 又反手丢回给UWorld::NotifyControlMessage

fce30531575762de0eebca5b37e4736f.png

ServerConnection, 和服务器的连接, 存在自然就是客户端.

嗯, 那if里面是客户端逻辑, else里面就是服务器逻辑.

fbfc3fa1719cd4bdc7b321a6d78e2392.png

废话不多说, 否管哪来的, 先检查!

1e9b3fb5f847e5117a705c834a3ced53.png

不合格? 简单, GoodBye! 走你!

1ef058ce6d910ef62613b97caef9163f.png

嗯, 检测合格了,.?

好孩子, 来, 再让我看看, 有没有先和我问个好, 打个招呼.

好, 看起来像个样子.

150e938e315ab59bc6082c10c28b7009.png
孤傲雕:UE4 网络相关之网络版本获取与比对

但我们这可不是什么随随便便的地方, 打招呼的礼仪对不对? 是现在最流行的, 最高贵最优雅的那一种吗?

不是???

???

...

滚回去学, 学完了再说...

bf7518381d5b53af2595dbe1993773db.png

然后客户端就收到了服务器的NMT_Upgrade消息

UEngine::TickWorldTravel转发到UPendingNetGame::Tick

UEngine::TickWorldTravel函数的转交到UPendingNetGame::Tick

UPendingNetGame再转交给对应的UNetConnection, 并进一步处理

最后, 又反手丢回给UPendingNetGame::NotifyControlMessage

44b177e9a202f40230b98d787ff91120.png

然后, 客户端就多播UEngine::BroadcastNetworkFailure, 类型为ENetworkFailure::OutdatedClient, 并记录对应错误日志

然后苦兮兮的更新版本去了.


第二回合 NMT_Hello

客户端好好的学了学最新的礼仪(更新到最新的客户端版本), 再一次向服务器友好礼貌打一声招呼!

Hello!

b8f4e39443772dc64f326604c955a15a.png

服务器再次看到了客户端.

嗯, 这次礼仪对了, 口令!

没有口令? ...

嗯, 对就是没有口令!

// 如果有口令, 会对口令进行验证, 并考虑是否传输进行加密, 见其他文章

616b7fe76c4821a5b4de50d7bd46399d.png

5ded6d46fae142469240dc236b6cbf60.png

通过FPlatformTime::Cycles获得一个数字, 取WinAPI QueryPerformanceCounter得到高精度计时器的值64位, 取其低32位

// server sends client challenge string to verify integrity
DEFINE_CONTROL_CHANNEL_MESSAGE(Challenge, 3, FString);

当网络状态有效, 就向客户端发送NMT_Challenge信息


同时调用SetExpectedClientLoginMsgType, 参数NMT_Login, 招呼打完了, 该干正事了 : 登录.


第三回合 NMT_Login

客户端又收到了服务器的NMT_Challenge消息

兜兜转转又回到了UPendingNetGame::NotifyControlMessage处理

e6c4e4a9a8efe05575f24988c95999d5.png

ae4233876e0a32a3002040d75e7bdd5c.png

然后PartialURL数据, Host清空, Port取默认值

嗯, 与服务器连接已经建立了, 这两个值没用处了

35b50261e9c7deaba987b030b41aa823.png

然后如图

d6faca2fd8f167e79e7f408de4a41938.png

ULocalPlayer::GetNickname有值时候, 添加一个Name参数

e9bf354c2e02a2ec45abac43ee07e6d7.png

ULocalPlayer::GetGameLoginOptions有值时, 添加对应参数

然后设置UConnectionPlayerID, 通过ULocalPlayer::GetPreferredUniqueNetId获得

例如 : L"DESKTOP-10Q6V1I-FCDB05414DB72C66F61B6E80E315FEA9"

f6659f0c025c81bece9f67f36a730d8b.png

然后获得OnlinePlatformName, 平台名称

4bba48d3ba309b3f70f2d63af7e9f5f6.png

273d49617e3009a454acfc6c6219b8dc.png

通过UGameInstance::GetOnlinePlatformName, 然后找UOnlineEngineInterface::GetDefaultOnlineSubsystemName获得

UOnlineEngineInterface是个接口类, 自然不同平台有对应的子类, 有不同的实现

21707c67ee3f6755591356a08250d654.png

98e294784dc430d4ef84c8623607f531.png

其中, UOnlineEngineInterfaceImpl是一个常用实现, 从IOnlineSubsystem中获得对应的平台名称

a858b4bd9685edfec33f787c1abc747a.png

738bfb2252c8cad12a70e8adfa071c60.png

同理又得, FOnlineSubsystemImpl又是IOnlineSubsystem的一个常用实现, SubsystemName该属性就是平台名称

c25729b3ae0741b5e47b5334c1f37803.png

889e283602b8fcdfac7d8d0e03c7d3c5.png

FOnlineSubsystemSteam为例, 它将STEAM_SUBSYSTEM作为SubsystemName传入, 最后平台名称, 也就是SubsystemName

参考文件EnginePluginsOnlineOnlineSubsystemSourcePublicOnlineSubsystemNames

里面定义了若干平台名称对应(如下图)

83b5e74a774bdf647909504efc45f00d.png

e6a9737471eb1c31eb969785bf8ef216.png

发送NMT_Login消息, 带有的字符串, 就都逐个介绍过.

再总的概况一下, 客户端向服务器发送包含玩家昵称, 网络ID, 连接地图参数, 平台名称的内容

给, 这是我的身份证明(玩家昵称与网络ID), 工作单位(平台名称), 来干什么的(连接参数), 放我进去吧!

服务器收到NMT_Login消息, 兜兜转转又走到UWorld::NotifyControlMessage处, 开始处理

6ceb7171f2d8733a8d89b00023cead2a.png

985fa245f27c86ecee7b2a28ee76ce2b.png

老规矩, 先检查

2f608d9f775dae1668176d00ba1ed3e6.png

好的, 检查通过, 我看看, 你写的什么.

嗯, 一个登陆请求, 想进去.

56f36ca1a603c2e4678eff30aeebd3dd.png

cc7606ed76c1bb56c00b8c1caa4a1900.png

ef5ecae0862fff40f81b6160639f61e5.png

先看看信息对不对, 并确认一下.

8bc7c409e2d7c39b22afed4095585836.png

23c1cb09972358fcba8309b82aacdf17.png

没问题, 好, 至少我觉得没问题.

我再问问你要去的地方(游戏地图内)允不允许你去.

AGameModeBase, 这个人的信息有问题没? 人你要不要? 有问题就让他滚蛋了.

// 这个时候就是Gameplay里面, 可以处理很多, 比如人满了, 不让进, 参数不对, 不让进等等

f3650caf59d37b35c4def347190aec1e.png

没问题!

听见了没, 还不快gu...等den, 没问题...

...

先生, 欢迎光临, 里边儿请!

e88c8b29aaf7033b7cc879cf21004d92.png

75180d8dfab145fd492334c8455621af.png

1590da6a4e41b53e28c0cdb59174918a.png

AGameModeBase, 招待下新人, 他要去哪里, 干什么?

82069cdee758d811a10a37d092302616.png

哦, 好的.

来, 看这张地图, 去这个地方(LevelName)做这个事 (GameMode),

56cbecd54ee687ffcf54045fb0b7f310.png

第四回合 NMT_Welcome

客户端又收到一条NMT_Welcome信息

还是在老地方UPendingNetGame::NotifyControlMessage处理

00ee06d5042ddace0c733e2babdd91e0.png

我可以进去了?

ac15cb4e82a8addf5fa07f2dfc0469be.png

嗯, 我要去这个地方干在这个事, 和之前想的不太一样啊!

// 客户端连接服务器时, 请求地图和GameMode是无效的, 以服务器为准

33bd3330e542d19541310ddbc85c45c3.png

07e7dace3277d061f7c297ca3fa6b8cd.png

赶紧过去报道!

a34f792ee9383ed4de68e3a2cb1f581f.png

我要过去报道了, 马上就到!

服务器收到NMT_Netspeed消息, 又走到UWorld::NotifyControlMessage

d02001456df0344d4c41b241b57f9ccc.png

3d96bc1300add2ec8ce7602948455041.png

日常检查一下, 然后设置一下客户端的网络速度

eb360cbb523d29d122c23e86f2558046.png

a7031aece202a92e5a10d05ff5e5b70a.png

收到, 速度还挺快!


第五回合 NMT_Join

03390f3f5f1acb022425b879c73e0294.png

客户端加载完地图, 准备正式加入服务器

f8987509a73f758ced9bf6eeb34fe9ab.png

我准备好了!

我准备好了!

服务器又收到一条NMT_Join信息, 兜兜转转还是UWorld::NotifyControlMessage在处理

检测, 通过略

ce6a85d359f75dfca6de6edd3b9fee09.png

3f135cc0622738085cf2300b76629b64.png

06a30677e5b1fa610d7c91d8803bb752.png

好了, 你的身份牌(PlayerController)生成了, 好好干!


经过这么多道手续, 客户端终于通过了身份验证, 和服务器建立起连接.

客户端就进入到AGameModeBase流程, 见其他文章


结语

  • 先这样, 之后再修改修改, 这篇文章憋了好久了... 关联的补充细节的都有一两篇了...
  • 骗赞了, 骗收藏了
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值