UE4.27, 揣摩源码, 网络同步 (一) 初始化,握手,登录
0. 计算机网络常识回顾
0.1. 四大层级,Socket抽象层
应用层->传输层->网络层->网络接口层
实际应用中,当我们使用socket技术后,关心的抽象是这样的
红绿分别代表服务器和客户端
应用层<-Socket抽象层->传输层<->...<->传输层<-Socket抽象层->应用层
应用层<-Socket抽象层->应用层
可以看出,Socket是一种层级极高的抽象层
它起源自UNIX系统,也承接了它们的文件哲学
因此socket的接口使用起来有一种,是在对文件操作的恍惚感,比如read(),write(),close()
win里通常是用send, recv替代write, read
网络操作和文件操作本质上都有一个缓冲池的环节,不过socket把深层的通常不需要客制化的细节藏起来了
0.1. Socket基本接口
服务器Server
初始化套接字 socket(传输层协议, 网络层协议)
绑定IP与端口 bind(IP:PORT)
监听 listen(...)
接受连接 accept(...)
send(), recv()
close()
客户端Client
初始化套接字 socket(传输层协议, 网络层协议)
发起连接 connect(...)
send(), recv()
close()
1. Socket初始化
1.1. SVO
UIpNetDriver获得套接字子系统,籍此创建平台特化的基本socket,然后经有InternalBSDSocketFactory创建最终的FSocket
(此套接字子系统不是单例模式里的那种gis子系统,看起来是个接口类,由loadmodule获得)
1.2. 堆栈调用
CreateAndBindSocket(...)
CreateSocketForProtocol(...)
CreateUniqueSocket(...)
FSocketSubsystemWindows::CreateSocket(...)
// 因平台特化
FSocketSubsystemBSD::CreateSocket(SocketType, SocketDescription, ProtocolType)
socket(af, type, protocal)
//windows的平台socket,需要指定
// af -[address_family] AF_INET/AF_INET6 地址族, ipv4,ipv6...
// type -[socket_type] Stream/Datagram/RAW 套接字类型, 流式, 数据报式, 原始式
// protocal -[protocal] TCP/UDP 传输协议tcp,udp,idp,rdp...
//反直觉的是,参数"报文类型"ProtocolType最终指定 [地址族af]
//而参数"套接字类型"SocketType最终指定了 [套接字类型type] 和 [传输协议protocal]
InternalBSDSocketFactory()
//将socket转化为ue的FSocket
//SocketDescription参数作为调试信息
1.3. Socket部分总结
服务器和客户端的连接采用的是socket抽象层
不论是哪个平台,哪个底层协议,ue都已经在onlinesubsystem包装好了,我们不再特别关心
2. 简单介绍握手和登录
2.1. 笔力有限,这几篇随笔着重于讨论网络同步的部分,至于前面的步骤,初始化 握手 登录,我们在此简单介绍
2.1.1. 初始化
// 初始化双端Socket并开始握手
2.1.1.1. 服务器
World持有NetDriver
NetDriver持有Socket
bind(作用上看,其实是等待UDP握手)
NetDriver持有Connectionless
Connectionless持有PacketHandler
2.1.1.2. 客户端:
PendingNetGame持有NetDriver
NetDriver持有NetConnection
NetDriver持有Socket
NetConnection接手Socket
NetConnection持有PacketHandler
PacketHandler开始握手
2.1.2. 握手
// 握手是为了确认连接的可靠性,最终让服务端为客户端创建UNetConnection
客户端 -> HandShakeBegin -> 服务端
客户端 <- ConnectChallenge <- 服务端
客户端 -> ChallengeResponse -> 服务端
客户端 <- ConnectChallengeAck <- 服务端
服务端为客户端创建NetConnection
2.1.3. 登录
// 在连接中进行登录流程
// 登录最后,客户端加载map并将NetDriver移交给World
// 登录最后,服务端将创建一个客户端的PlayerController
客户端 -> NMT_Hello -> 服务端
客户端 <- NMT_Challenge <- 服务端
客户端 -> NMT_Login -> 服务端
客户端 <- NMT_Welcome <- 服务端
客户端 -> NMT_Netspeed -> 服务端
// 客户端LoadMap
客户端 -> NMT_Join -> 服务端
// 服务端SpawnPlayActor