开始的地方:网关服务器
OuterMessageDispatcher,判断是iActorMessage消息,这里处理actor消息。
case IActorMessage iActorMessage: // gate session收到actor消息直接转发给actor自己去处理
{
long unitId = session.GetComponent<SessionPlayerComponent>().Player.UnitId;//获取unit在map服务器的unitid
ActorMessageSender actorMessageSender = Game.Scene.GetComponent<ActorMessageSenderComponent>().Get(unitId);//用unit在map服务器的unitid来创建ActorMessageSender ,这个ActorMessageSender内会根据unitid获取map服务器的session,并向map服务器的session发送actor消息
actorMessageSender.Send(iActorMessage);//开始向map服务器的session发送actor消息
return;
}
主题来了,actor消息的发送器的处理流程
ActorMessageSender
1,自身不断执行UpdateAsync,处理流程
1.1UpdateAsync:
public static async void UpdateAsync(this ActorMessageSender self)
{
try
{
while (true)
{
ActorTask actorTask = await self.GetAsync();//会在这等待GetAsync返回值
if (self.IsDisposed)
{
return;
}
if (actorTask.ActorMessage == null)
{
return;
}
await self.RunTask(actorTask);//创建线程,执行RunTask函数,继续下一个循环
}
}
catch (Exception e)
{
Log.Error(e);
}
}
1.2GetAsync:
private static Task<ActorTask> GetAsync(this ActorMessageSender self)
{
if (self.WaitingTasks.Count > 0)//刚开始没有发过来消息时,等待任务数量是0
{
ActorTask task = self.WaitingTasks.Peek();
return Task.FromResult(task);
}
self.Tcs = new TaskCompletionSource<ActorTask>();//等待任务数量是0时,会执行这里,创建一个TaskCompletionSource,作用是,可以在其他地方调用SetResult方法,给task赋值
return self.Tcs.Task;//这里将self.Tcs里的task返回,但是没有调用SetResult方法,所以在这里会等待,激活条件是2.3AllowGet中, t.SetResult(task);这句话
}
1.3RunTask:
private static async Task RunTask(this ActorMessageSender self, ActorTask task)
{
Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(self.Address);
task.ActorMessage.ActorId = self.ActorId;
IResponse response = await session.Call(task.ActorMessage);
// 发送成功
switch (response.Error)
{
case ErrorCode.ERR_NotFoundActor:
// 如果没找到Actor,重试
++self.FailTimes;
// 失败MaxFailTimes次则清空actor发送队列,返回失败
if (self.FailTimes > self.MaxFailTimes)
{
// 失败直接删除actorproxy
Log.Info($"actor send message fail, actorid: {self.Id}");
self.Error = response.Error;
self.GetParent<ActorMessageSenderComponent>().Remove(self.Id);
return;
}
// 等待1s再发送
await Game.Scene.GetComponent<TimerComponent>().WaitAsync(1000);
self.ActorId = await Game.Scene.GetComponent<LocationProxyComponent>().Get(self.Id);
self.Address = Game.Scene.GetComponent<StartConfigComponent>()
.Get(IdGenerater.GetAppIdFromId(self.ActorId))
.GetComponent<InnerConfig>().IPEndPoint;
self.AllowGet();
return;
case ErrorCode.ERR_ActorNoMailBoxComponent:
self.Error = response.Error;
self.GetParent<ActorMessageSenderComponent>().Remove(self.Id);
return;
default:
self.LastSendTime = TimeHelper.Now();
self.FailTimes = 0;
self.WaitingTasks.Dequeue();
task.Tcs?.SetResult(response);//task.Tcs激活返回值处,使调用return task.Tcs.Task;这里继续执行。2send并没有用到,3call用到了
return;
}
}
2,外面主动调用Send函数,处理流程
2.1Send:
public static void Send(this ActorMessageSender self, IActorMessage message)
{
ActorTask task = new ActorTask(message);//构造一个ActorTask
self.Add(task);//将ActorTask 添加到等待队列
}
2.2Add:
private static void Add(this ActorMessageSender self, ActorTask task)
{
if (self.IsDisposed)
{
throw new Exception("ActorProxy Disposed! dont hold actorproxy");
}
self.WaitingTasks.Enqueue(task);//添加进等待队列
// failtimes > 0表示正在重试,这时候不能加到正在发送队列,默认是等于0的。
if (self.FailTimes == 0)
{
self.AllowGet();//从等待队列里取任务,当然会在里面做判断,什么情况下可以取
}
}
2.3AllowGet:
private static void AllowGet(this ActorMessageSender self)
{
if (self.Tcs == null || self.WaitingTasks.Count <= 0)//self.Tcs是空,等待队列是空,都会返回,不做任何处理。在这里,
也就是说,如果队列里有等待任务,是不允许下面取出任务的;并且self.Tcs 这个任务没有创建,也不允许下面取出任务的,也就是说明,这个actor消息的发送器正在处理消息中
{
return;
}
ActorTask task = self.WaitingTasks.Peek();//从等待队列取出任务,
var t = self.Tcs;//将任务给本函数
self.Tcs = null;//将自身的任务置空
t.SetResult(task);//上面的 1.2GetAsync方法中 ,停在这里return self.Tcs.Task;,使这里激活,继续执行下去
}
3外面主动调用Call函数,处理流程
3.1Call:流程和send类似,只有 多了一个返回值,return task.Tcs.Task;
public static Task<IResponse> Call(this ActorMessageSender self, IActorRequest request)
{
TaskCompletionSource<IResponse> tcs = new TaskCompletionSource<IResponse>();//创建一个TaskCompletionSource,用来返回task
ActorTask task = new ActorTask(request, tcs);//创建任务
self.Add(task);//添加任务
return task.Tcs.Task;//返回task结果,在这里会阻塞,直到1.3RunTask中 task.Tcs?.SetResult(response)执行后,才会激活,继续执行
}
3.2Add:
同上
3.3AllowGet:
同上