ET|11 网络通讯
网络消息的定义
注意,ET 8.0仍然是通过proto定义消息的,但是会通过工具转为cs,最后序列化/反序列化的时候使用的是memory pack
协议定义在Config/Proto目录
// ResponseType NetClient2Main_Login
message Main2NetClient_Login // IRequest
{
int32 RpcId = 1;
int32 OwnerFiberId = 2;
string Account = 3; // 账号
string Password = 4; // 密码
}
message NetClient2Main_Login // IResponse
{
int32 RpcId = 1;
int32 Error = 2;
string Message = 3;
int64 PlayerId = 4;
}
这只是作为一个例子,具体的含义以后再说
服务器连接流程
ET管理的核心之一就是Scene,我们可以找到一个枚举,定义了所有Scene的类型
[Flags]
public enum SceneType: long
{
None = 0,
Main = 1, // 主纤程,一个进程一个, 初始化从这里开始
NetInner = 1 << 2, // 负责进程间消息通信
Realm = 1 << 3,
Gate = 1 << 4,
Http = 1 << 5,
Location = 1 << 6,
Map = 1 << 7,
Router = 1 << 8,
RouterManager = 1 << 9,
Robot = 1 << 10,
BenchmarkClient = 1 << 11,
BenchmarkServer = 1 << 12,
Match = 1 << 14,
Room = 1 << 15,
LockStepClient = 1 << 16,
LockStepServer = 1 << 17,
RoomRoot = 1 << 18,
Watcher = 1 << 19,
// 客户端
Demo = 1 << 30,
Current = 1L << 31,
LockStep = 1L << 32,
LockStepView = 1L << 33,
DemoView = 1L << 34,
NetClient = 1L << 35,
All = long.MaxValue,
}
这些类型和启服流程是息息相关的
配置定义 Config\Excel\StartConfig\Localhost
打开StartSceneConfig.xlsx,这里面是所有运行入口会创建的Scene,一共十二个,也就是服务器一启动就会创建12个Fiber
获取软路由地址
如前面所说,客户端一般有两个Fiber,业务层Fiber发起登录请求,先转发给客户端本地网络层,此时网络层向RouterManager进行一次HTTP请求,获取到所有软路由的地址,也就是配置表中的四个
客户端与服务端所有的消息通信,都必须通过软路由转发
请求登录令牌
获取到软路由地址之后,客户端向Realm服请求分配网关,并由Realm服向网关服请求一个网关令牌,最后返回给客户端
最后客户端持有令牌,直接连接对应的网关,此时会创建对应的playerId映射
Map服
虽然名字叫做Map服,但其实不是地图服务器,叫做GameLogic服更加恰当,Gate所创建的Unit,可以说是每一个客户端在服务器上的映射,每一个客户端处理Unit都会被放到某一个Map服上,网关服可以通过Location服务器定位客户端对应的Unit,也可以说,每一个Unit都对应一个玩家
Actor模型与Fiber通讯
对于ET而言,只要挂载了MailBoxComponent的Entity,那都可以认为是一个Actor,而这个Actor上的任何东西你都可以当做是一个Unit,只要你想
比如说我们的登录组件,他就可以是一个Unit,我们通过这个组件可以进行登录消息的收发
同一个进程的Fiber进行交互,这里的ProcessInnerSender只是一个消息队列
不同进程之间的Fiber进行交互,每个进程都会内涵一个InnerFiber,该进程内的所有Fiber先通过消息队列和InnerFiber交互,InnerFiber再和其他进行的InnerFiber交互
不同Fiber之间的Unit如何确定位置呢?比如Fiber1的Unit1想给Fiber2的Unit6发送消息。
每一个unit都关联了一个结构体ActorId,这个结构体可以定位Unit的位置信息
public partial struct ActorId
{
public Address Address;
// 实例ID,一般是Entity的,每一个Entity都不同
public long InstanceId;
}
public partial struct Address
{
// 这个似乎默认是1
public int Process;
// 纤程ID
public int Fiber;
}
基本上就是FiberID+InstanceID可以锁定唯一的Unit