登录流程

UILoginComponentSystem

更多框架细节先不讨论,只要知道,当打开登录UI后,会执行UILoginComponentAwakeSystem中的Awake方法

[ObjectSystem]
public class UILoginComponentAwakeSystem : AwakeSystem<UILoginComponent>
{
   public override void Awake(UILoginComponent self)
   {
      ReferenceCollector rc = self.GetParent<UI>().GameObject.GetComponent<ReferenceCollector>();
      self.loginBtn = rc.Get<GameObject>("LoginBtn");
      
      self.loginBtn.GetComponent<Button>().onClick.AddListener(()=> { self.OnLogin(); });
      self.account = rc.Get<GameObject>("Account");
      self.password = rc.Get<GameObject>("Password");
   }
}

// 真正的登录逻辑
[FriendClass(typeof(UILoginComponent))]
public static class UILoginComponentSystem
{
   public static void OnLogin(this UILoginComponent self)
   {
      LoginHelper.Login(
         self.DomainScene(), 
         ConstValue.LoginAddress, 
         self.account.GetComponent<InputField>().text, 
         self.password.GetComponent<InputField>().text).Coroutine();
   }
}

创建Session

// Session可以理解为一个会话
Session session = null;
session = zoneScene.GetComponent<NetKcpComponent>().Create(NetworkHelper.ToIPEndPoint(address));

创建了一个Session,并挂载到NetKcpComponent下,Session也是一个Entity

public static Session Create(this NetKcpComponent self, IPEndPoint realIPEndPoint)
{
    long channelId = RandomHelper.RandInt64();
    Session session = self.AddChildWithId<Session, AService>(channelId, self.Service);
    session.RemoteAddress = realIPEndPoint;
    session.AddComponent<SessionIdleCheckerComponent, int>(NetThreadComponent.checkInteral);
    
    self.Service.GetOrCreate(session.Id, realIPEndPoint);

    return session;
}

AServer : Abstract Server 服务器基类

TServer : TCP Server TCP连接

KServer : KCP Server KCP连接

基类中有一个GetOrCreate方法,是用于创建连接的,我们可以观察TServer

虽然这个组件叫做NetKcpCompoent,但观察他的Awake方法,添加的连接服务是TCP服务…

public class NetKcpComponentAwakeSystem: AwakeSystem<NetKcpComponent, int>
{
    public override void Awake(NetKcpComponent self, int sessionStreamDispatcherType)
    {
        ...
        self.Service = 
            new TService(NetThreadComponent.Instance.ThreadSynchronizationContext, ServiceType.Outer);

    }
}

创建了一个TChannel(TCP Channel)

private TChannel Create(IPEndPoint ipEndPoint, long id)
{
   TChannel channel = new TChannel(id, ipEndPoint, this);
   this.idChannels.Add(channel.Id, channel);
   return channel;
}

可以查看TChannel的构造函数,确实是TCP + IPV4

public TChannel(long id, IPEndPoint ipEndPoint, TService service)
{
    ...
   this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	...
}

发送登录请求

Call是发送,具体的处理则在服务端

r2CLogin = (R2C_Login) await session.Call(new C2R_Login() { Account = account, Password = password });

服务器代码中有这样一个类,用于处理客户端登录请求

image-20230709181946097

public class C2R_LoginHandler : AMRpcHandler<C2R_Login, R2C_Login>
{
   protected override async ETTask Run(Session session, C2R_Login request, R2C_Login response, Action reply)
   {
      // 随机分配一个Gate
      StartSceneConfig config = RealmGateAddressHelper.GetGate(session.DomainZone());
      Log.Debug($"gate address: {MongoHelper.ToJson(config)}");
      
      // 向gate请求一个key,客户端可以拿着这个key连接gate
      G2R_GetLoginKey g2RGetLoginKey = (G2R_GetLoginKey) await ActorMessageSenderComponent.Instance.Call(
         config.InstanceId, new R2G_GetLoginKey() {Account = request.Account});

      response.Address = config.OuterIPPort.ToString();
      response.Key = g2RGetLoginKey.Key;
      response.GateId = g2RGetLoginKey.GateId;
      reply();
   }
}

可以发现服务器返回了一个GateId给客户端

客户端处理结果

当拿到服务器结果后,客户端首先结束了第一次会话

然后再次创建会话

session?.Dispose();

// 创建一个gate Session,并且保存到SessionComponent中
Session gateSession = zoneScene.GetComponent<NetKcpComponent>().Create(NetworkHelper.ToIPEndPoint(r2CLogin.Address));
gateSession.AddComponent<PingComponent>();
zoneScene.AddComponent<SessionComponent>().Session = gateSession;

服务器架构演变

一代

N个客户端连接1个服务器

服务器直接读写文件IO

image-20230709185343642

二代

N个客户端连接M个服务端(区服)

服务端读写数据库

image-20230709185427768

三代

N个客户端连接M个网关

客户端数据由网关转发给服务器

网关只负责连接(接收/转发)

服务器只负责功能逻辑处理(业务逻辑)

数据库代理只负责DB读写(数据存储)

image-20230709185459759

后续又进行了一次演变

image-20230709185929048

最后,客户端通过网关ID,请求连接网关

G2C_LoginGate g2CLoginGate = (G2C_LoginGate)await gateSession.Call(
    new C2G_LoginGate() { Key = r2CLogin.Key, GateId = r2CLogin.GateId});

整个登录流程大概如下

image-20230709191645856

ET框架设计

image-20230709192022227