mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
[+] 接入ET8服务端
[+] 接入ET8服务端
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ET.Server
|
||||
{
|
||||
[ActorMessageHandler(SceneType.NetInner)]
|
||||
public class A2NetInner_MessageHandler: ActorMessageHandler<Scene, A2NetInner_Message>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, A2NetInner_Message innerMessage)
|
||||
{
|
||||
root.GetComponent<ActorOuterComponent>().Send(innerMessage.ActorId, innerMessage.MessageObject);
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c88c8f9b180ab7f4b8c92e3cbdd3260f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace ET.Server
|
||||
{
|
||||
[ActorMessageHandler(SceneType.NetInner)]
|
||||
public class A2NetInner_RequestHandler: ActorMessageHandler<Scene, A2NetInner_Request, A2NetInner_Response>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, A2NetInner_Request request, A2NetInner_Response response)
|
||||
{
|
||||
response.MessageObject = await root.GetComponent<ActorOuterComponent>().Call(request.ActorId, request.MessageObject, request.NeedException);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd158674e3aca934cb0bf40359f60577
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,246 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace ET.Server
|
||||
{
|
||||
[EntitySystemOf(typeof(ActorOuterComponent))]
|
||||
[FriendOf(typeof(ActorOuterComponent))]
|
||||
public static partial class ActorOuterComponentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this ActorOuterComponent self, IPEndPoint address)
|
||||
{
|
||||
switch (self.InnerProtocol)
|
||||
{
|
||||
case NetworkProtocol.TCP:
|
||||
{
|
||||
self.AService = new TService(address, ServiceType.Inner);
|
||||
break;
|
||||
}
|
||||
case NetworkProtocol.KCP:
|
||||
{
|
||||
self.AService = new KService(address, ServiceType.Inner);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.AService.AcceptCallback = self.OnAccept;
|
||||
self.AService.ReadCallback = self.OnRead;
|
||||
self.AService.ErrorCallback = self.OnError;
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Update(this ActorOuterComponent self)
|
||||
{
|
||||
self.AService.Update();
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Destroy(this ActorOuterComponent self)
|
||||
{
|
||||
self.AService.Dispose();
|
||||
}
|
||||
|
||||
private static void OnRead(this ActorOuterComponent self, long channelId, ActorId actorId, object message)
|
||||
{
|
||||
Session session = self.GetChild<Session>(channelId);
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
session.LastRecvTime = self.Fiber().TimeInfo.ClientFrameTime();
|
||||
|
||||
self.HandleMessage(actorId, message).Coroutine();
|
||||
}
|
||||
|
||||
private static async ETTask HandleMessage(this ActorOuterComponent self, ActorId actorId, object message)
|
||||
{
|
||||
Fiber fiber = self.Fiber();
|
||||
int fromProcess = actorId.Process;
|
||||
actorId.Process = fiber.Process;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case IActorResponse iActorResponse:
|
||||
{
|
||||
self.HandleIActorResponse(iActorResponse);
|
||||
return;
|
||||
}
|
||||
case IActorLocationRequest iActorRequest:
|
||||
{
|
||||
IActorResponse response = await fiber.ActorInnerComponent.Call(actorId, iActorRequest, false);
|
||||
actorId.Process = fromProcess;
|
||||
self.Send(actorId, response);
|
||||
break;
|
||||
}
|
||||
case IActorRequest iActorRequest:
|
||||
{
|
||||
IActorResponse response = await fiber.ActorInnerComponent.Call(actorId, iActorRequest);
|
||||
actorId.Process = fromProcess;
|
||||
self.Send(actorId, response);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
ActorMessageQueue.Instance.Send(actorId, (MessageObject)message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnError(this ActorOuterComponent self, long channelId, int error)
|
||||
{
|
||||
Session session = self.GetChild<Session>(channelId);
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
session.Error = error;
|
||||
session.Dispose();
|
||||
}
|
||||
|
||||
// 这个channelId是由CreateAcceptChannelId生成的
|
||||
private static void OnAccept(this ActorOuterComponent self, long channelId, IPEndPoint ipEndPoint)
|
||||
{
|
||||
Session session = self.AddChildWithId<Session, AService>(channelId, self.AService);
|
||||
session.RemoteAddress = ipEndPoint;
|
||||
//session.AddComponent<SessionIdleCheckerComponent, int, int, int>(NetThreadComponent.checkInteral, NetThreadComponent.recvMaxIdleTime, NetThreadComponent.sendMaxIdleTime);
|
||||
}
|
||||
|
||||
private static Session CreateInner(this ActorOuterComponent self, long channelId, IPEndPoint ipEndPoint)
|
||||
{
|
||||
Session session = self.AddChildWithId<Session, AService>(channelId, self.AService);
|
||||
session.RemoteAddress = ipEndPoint;
|
||||
self.AService.Create(channelId, ipEndPoint);
|
||||
|
||||
//session.AddComponent<InnerPingComponent>();
|
||||
//session.AddComponent<SessionIdleCheckerComponent, int, int, int>(NetThreadComponent.checkInteral, NetThreadComponent.recvMaxIdleTime, NetThreadComponent.sendMaxIdleTime);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
// 内网actor session,channelId是进程号
|
||||
private static Session Get(this ActorOuterComponent self, long channelId)
|
||||
{
|
||||
Session session = self.GetChild<Session>(channelId);
|
||||
if (session != null)
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
IPEndPoint ipEndPoint = StartSceneConfigCategory.Instance.Get((int) channelId).InnerIPPort;
|
||||
session = self.CreateInner(channelId, ipEndPoint);
|
||||
return session;
|
||||
}
|
||||
|
||||
public static void HandleIActorResponse(this ActorOuterComponent self, IActorResponse response)
|
||||
{
|
||||
if (!self.requestCallback.Remove(response.RpcId, out ActorMessageSender actorMessageSender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
Run(actorMessageSender, response);
|
||||
}
|
||||
|
||||
private static void Run(ActorMessageSender self, IActorResponse response)
|
||||
{
|
||||
if (response.Error == ErrorCore.ERR_ActorTimeout)
|
||||
{
|
||||
self.Tcs.SetException(new Exception($"Rpc error: request, 注意Actor消息超时,请注意查看是否死锁或者没有reply: actorId: {self.ActorId} {self.Request}, response: {response}"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.NeedException && ErrorCore.IsRpcNeedThrowException(response.Error))
|
||||
{
|
||||
self.Tcs.SetException(new Exception($"Rpc error: actorId: {self.ActorId} request: {self.Request}, response: {response}"));
|
||||
return;
|
||||
}
|
||||
|
||||
self.Tcs.SetResult(response);
|
||||
}
|
||||
|
||||
public static void Send(this ActorOuterComponent self, ActorId actorId, IActorMessage message)
|
||||
{
|
||||
self.SendInner(actorId, message as MessageObject);
|
||||
}
|
||||
|
||||
private static void SendInner(this ActorOuterComponent self, ActorId actorId, MessageObject message)
|
||||
{
|
||||
if (actorId == default)
|
||||
{
|
||||
throw new Exception($"actor id is 0: {message}");
|
||||
}
|
||||
|
||||
Fiber fiber = self.Fiber();
|
||||
// 如果发向同一个进程,则报错
|
||||
if (actorId.Process == fiber.Process)
|
||||
{
|
||||
throw new Exception($"actor is the same process: {fiber.Process} {actorId.Process}");
|
||||
}
|
||||
|
||||
StartSceneConfig startSceneConfig = StartSceneConfigCategory.Instance.NetInners[actorId.Process];
|
||||
Session session = self.Get(startSceneConfig.Id);
|
||||
actorId.Process = fiber.Process;
|
||||
session.Send(actorId, message);
|
||||
}
|
||||
|
||||
private static int GetRpcId(this ActorOuterComponent self)
|
||||
{
|
||||
return ++self.RpcId;
|
||||
}
|
||||
|
||||
public static async ETTask<IActorResponse> Call(this ActorOuterComponent self, ActorId actorId, IActorRequest iActorRequest, bool needException = true)
|
||||
{
|
||||
if (actorId == default)
|
||||
{
|
||||
throw new Exception($"actor id is 0: {iActorRequest}");
|
||||
}
|
||||
Fiber fiber = self.Fiber();
|
||||
|
||||
int rpcId = self.GetRpcId();
|
||||
|
||||
var tcs = ETTask<IActorResponse>.Create(true);
|
||||
|
||||
self.requestCallback.Add(self.RpcId, new ActorMessageSender(actorId, iActorRequest, tcs, needException));
|
||||
|
||||
self.SendInner(actorId, iActorRequest as MessageObject);
|
||||
|
||||
async ETTask Timeout()
|
||||
{
|
||||
await fiber.TimerComponent.WaitAsync(ActorOuterComponent.TIMEOUT_TIME);
|
||||
if (!self.requestCallback.Remove(rpcId, out ActorMessageSender action))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (needException)
|
||||
{
|
||||
action.Tcs.SetException(new Exception($"actor sender timeout: {iActorRequest}"));
|
||||
}
|
||||
else
|
||||
{
|
||||
IActorResponse response = ActorHelper.CreateResponse(iActorRequest, ErrorCore.ERR_Timeout);
|
||||
action.Tcs.SetResult(response);
|
||||
}
|
||||
}
|
||||
|
||||
Timeout().Coroutine();
|
||||
|
||||
long beginTime = fiber.TimeInfo.ServerFrameTime();
|
||||
|
||||
IActorResponse response = await tcs;
|
||||
|
||||
long endTime = fiber.TimeInfo.ServerFrameTime();
|
||||
|
||||
long costTime = endTime - beginTime;
|
||||
if (costTime > 200)
|
||||
{
|
||||
Log.Warning($"actor rpc time > 200: {costTime} {iActorRequest}");
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5950c6f1f1733d846864c5f87cc48038
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace ET
|
||||
{
|
||||
[FriendOf(typeof(ActorSenderComponent))]
|
||||
public static partial class ActorSenderComponentSystem
|
||||
{
|
||||
public static void Send(this ActorSenderComponent self, ActorId actorId, IActorMessage message)
|
||||
{
|
||||
Fiber fiber = self.Fiber();
|
||||
// 如果发向同一个进程,则扔到消息队列中
|
||||
if (actorId.Process == fiber.Process)
|
||||
{
|
||||
ActorMessageQueue.Instance.Send(fiber.Address, actorId, (MessageObject)message);
|
||||
return;
|
||||
}
|
||||
|
||||
// 发给NetInner纤程
|
||||
A2NetInner_Message a2NetInnerMessage = A2NetInner_Message.Create();
|
||||
a2NetInnerMessage.FromAddress = fiber.Address;
|
||||
a2NetInnerMessage.ActorId = actorId;
|
||||
a2NetInnerMessage.MessageObject = message;
|
||||
|
||||
StartSceneConfig startSceneConfig = StartSceneConfigCategory.Instance.NetInners[fiber.Process];
|
||||
ActorMessageQueue.Instance.Send(startSceneConfig.ActorId, a2NetInnerMessage);
|
||||
}
|
||||
|
||||
public static int GetRpcId(this ActorSenderComponent self)
|
||||
{
|
||||
return ++self.RpcId;
|
||||
}
|
||||
|
||||
public static async ETTask<IActorResponse> Call(
|
||||
this ActorSenderComponent self,
|
||||
ActorId actorId,
|
||||
IActorRequest request,
|
||||
bool needException = true
|
||||
)
|
||||
{
|
||||
request.RpcId = self.GetRpcId();
|
||||
|
||||
if (actorId == default)
|
||||
{
|
||||
throw new Exception($"actor id is 0: {request}");
|
||||
}
|
||||
|
||||
return await self.Call(actorId, request.RpcId, request, needException);
|
||||
}
|
||||
|
||||
public static async ETTask<IActorResponse> Call(
|
||||
this ActorSenderComponent self,
|
||||
ActorId actorId,
|
||||
int rpcId,
|
||||
IActorRequest iActorRequest,
|
||||
bool needException = true
|
||||
)
|
||||
{
|
||||
if (actorId == default)
|
||||
{
|
||||
throw new Exception($"actor id is 0: {iActorRequest}");
|
||||
}
|
||||
Fiber fiber = self.Fiber();
|
||||
if (fiber.Process == actorId.Process)
|
||||
{
|
||||
return await fiber.Root.GetComponent<ActorInnerComponent>().Call(actorId, rpcId, iActorRequest, needException);
|
||||
}
|
||||
|
||||
// 发给NetInner纤程
|
||||
A2NetInner_Request a2NetInner_Request = A2NetInner_Request.Create();
|
||||
a2NetInner_Request.ActorId = actorId;
|
||||
a2NetInner_Request.MessageObject = iActorRequest;
|
||||
a2NetInner_Request.NeedException = needException;
|
||||
StartSceneConfig startSceneConfig = StartSceneConfigCategory.Instance.NetInners[fiber.Process];
|
||||
A2NetInner_Response response = await fiber.Root.GetComponent<ActorSenderComponent>().Call(
|
||||
startSceneConfig.ActorId, a2NetInner_Request, needException: a2NetInner_Request.NeedException) as A2NetInner_Response;
|
||||
return response.MessageObject;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1dbffb76761f34144a9e283ec16a499a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,72 @@
|
||||
using System.Net;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace ET.Server
|
||||
{
|
||||
[EntitySystemOf(typeof(NetServerComponent))]
|
||||
[FriendOf(typeof(NetServerComponent))]
|
||||
public static partial class NetServerComponentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this NetServerComponent self, IPEndPoint address)
|
||||
{
|
||||
self.AService = new KService(address, ServiceType.Outer);
|
||||
self.AService.AcceptCallback = self.OnAccept;
|
||||
self.AService.ReadCallback = self.OnRead;
|
||||
self.AService.ErrorCallback = self.OnError;
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Update(this NetServerComponent self)
|
||||
{
|
||||
self.AService.Update();
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Destroy(this NetServerComponent self)
|
||||
{
|
||||
self.AService.Dispose();
|
||||
}
|
||||
|
||||
private static void OnError(this NetServerComponent self, long channelId, int error)
|
||||
{
|
||||
Session session = self.GetChild<Session>(channelId);
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
session.Error = error;
|
||||
session.Dispose();
|
||||
}
|
||||
|
||||
// 这个channelId是由CreateAcceptChannelId生成的
|
||||
private static void OnAccept(this NetServerComponent self, long channelId, IPEndPoint ipEndPoint)
|
||||
{
|
||||
Session session = self.AddChildWithId<Session, AService>(channelId, self.AService);
|
||||
session.RemoteAddress = ipEndPoint;
|
||||
|
||||
if (self.IScene.SceneType != SceneType.BenchmarkServer)
|
||||
{
|
||||
// 挂上这个组件,5秒就会删除session,所以客户端验证完成要删除这个组件。该组件的作用就是防止外挂一直连接不发消息也不进行权限验证
|
||||
session.AddComponent<SessionAcceptTimeoutComponent>();
|
||||
// 客户端连接,2秒检查一次recv消息,10秒没有消息则断开
|
||||
session.AddComponent<SessionIdleCheckerComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnRead(this NetServerComponent self, long channelId, ActorId actorId, object message)
|
||||
{
|
||||
Session session = self.GetChild<Session>(channelId);
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
session.LastRecvTime = self.Fiber().TimeInfo.ClientNow();
|
||||
|
||||
Log.Debug(message.ToJson());
|
||||
|
||||
EventSystem.Instance.Publish(self.Scene(), new NetServerComponentOnRead() {Session = session, Message = message});
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 40d0bddfefa8ce34a8349977968fc0cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user