Fantasy业务代码执行之Run方法分析

一、开启网络监听

Fantasy.Net\Runtime\Core\Network\Protocol\KCP\Server\KCPServerNetwork.cs:72

       public void Initialize(NetworkTarget networkTarget, IPEndPoint address){_startTime = TimeHelper.Now;Settings = KCPSettings.Create(networkTarget);base.Initialize(NetworkType.Server, NetworkProtocolType.KCP, networkTarget);_socket = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp);_socket.Blocking = false;_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);if (address.AddressFamily == AddressFamily.InterNetworkV6){_socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);}_socket.Blocking = false;_socket.Bind(address);_socket.SetSocketBufferToOsLimit();_socket.SetSioUdpConnReset();ReadPipeDataAsync().Coroutine();ReceiveSocketAsync().Coroutine();Log.Info($"SceneConfigId = {Scene.SceneConfigId} networkTarget = {networkTarget.ToString()} KCPServer Listen {address}");}

二、收到数据

Fantasy.Net\Runtime\Core\Network\Protocol\TCP\Server\TCPServerNetworkChannel.cs:127

private async FTask ReadPipeDataAsync(){var pipeReader = _pipe.Reader;while (!_cancellationTokenSource.IsCancellationRequested){ReadResult result = default;try{result = await pipeReader.ReadAsync(_cancellationTokenSource.Token);}catch (OperationCanceledException){// 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。break;}var buffer = result.Buffer;var consumed = buffer.Start;var examined = buffer.End;while (TryReadMessage(ref buffer, out var message)){ReceiveData(ref message);consumed = buffer.Start;}if (result.IsCompleted){break;}pipeReader.AdvanceTo(consumed, examined);}await pipeReader.CompleteAsync();}

三、进入到自己封装的Session

一个Scene中的Socket监听到网络事件

Fantasy.Net\Runtime\Core\Network\Protocol\TCP\Server\TCPServerNetworkChannel.cs:185

        private void ReceiveData(ref ReadOnlyMemory<byte> buffer){try{while (_packetParser.UnPack(ref buffer, out var packInfo)){if (_cancellationTokenSource.IsCancellationRequested){return;}Session.Receive(packInfo);}}catch (ScanException e){Log.Warning($"RemoteAddress:{RemoteEndPoint} \n{e}");Dispose();}catch (Exception e){Log.Error($"RemoteAddress:{RemoteEndPoint} \n{e}");Dispose();}}

四、其实就是直接开始处理

Fantasy.Net\Runtime\Core\Network\Session\Session.cs:240

internal void Receive(APackInfo packInfo){if (IsDisposed){return;}LastReceiveTime = TimeHelper.Now;try{NetworkMessageScheduler.Scheduler(this, packInfo);}catch (Exception e){// 如果解析失败,只有一种可能,那就是有人恶意发包。// 所以这里强制关闭了当前连接。不让对方一直发包。Dispose();Log.Error(e);}}

五、处理的时候,其实是不阻塞,这样子能快速接下一个消息

Fantasy.Net\Runtime\Core\Network\Message\Scheduler\OuterMessageScheduler.cs:43

  public override void Scheduler(Session session, APackInfo packInfo){HandlerAsync(session, packInfo).Coroutine();}

六、直接进入自己的MessageHandler进行处理

Fantasy.Net\Runtime\Core\Network\Message\Scheduler\OuterMessageScheduler.cs:48

private async FTask HandlerAsync(Session session, APackInfo packInfo){if (session.IsDisposed){return;}switch (packInfo.OpCodeIdStruct.Protocol){case OpCodeType.OuterPingRequest:{// 注意心跳目前只有外网才才会有、内网之间不需要心跳。session.LastReceiveTime = TimeHelper.Now;_pingResponse.Now = session.LastReceiveTime;using (packInfo){session.Send(_pingResponse, packInfo.RpcId);}return;}case OpCodeType.OuterMessage:case OpCodeType.OuterRequest:{var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode);try{if (messageType == null){throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}var message = packInfo.Deserialize(messageType);MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode);}catch (Exception e){Log.Error($"ANetworkMessageScheduler OuterResponse error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}");}finally{packInfo.Dispose();}return;}case OpCodeType.OuterResponse:{using (packInfo){var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode);if (messageType == null){throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}NetworkMessagingComponent.ResponseHandler(packInfo.RpcId, (IResponse)packInfo.Deserialize(messageType));}return;}case OpCodeType.OuterAddressableMessage:{var packInfoPackInfoId = packInfo.PackInfoId;try{var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode);if (messageType == null){throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}var addressableRouteComponent = session.GetComponent<AddressableRouteComponent>();if (addressableRouteComponent == null){throw new Exception("OuterMessageScheduler error session does not have an AddressableRouteComponent component");}await addressableRouteComponent.Send(messageType, packInfo);}finally{if (packInfo.PackInfoId == packInfoPackInfoId){packInfo.Dispose();}}return;}case OpCodeType.OuterAddressableRequest:{var packInfoPackInfoId = packInfo.PackInfoId;try{var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode);if (messageType == null){throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}var addressableRouteComponent = session.GetComponent<AddressableRouteComponent>();if (addressableRouteComponent == null){throw new Exception("OuterMessageScheduler error session does not have an AddressableRouteComponent component");}var rpcId = packInfo.RpcId;var runtimeId = session.RunTimeId;var response = await addressableRouteComponent.Call(messageType, packInfo);// session可能已经断开了,所以这里需要判断if (session.RunTimeId == runtimeId){session.Send(response, rpcId);}}finally{if (packInfo.PackInfoId == packInfoPackInfoId){packInfo.Dispose();}}return;}case OpCodeType.OuterCustomRouteMessage:{var packInfoProtocolCode = packInfo.ProtocolCode;var packInfoPackInfoId = packInfo.PackInfoId;try{if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType)){throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode);if (messageType == null){throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}var routeComponent = session.GetComponent<RouteComponent>();if (routeComponent == null){throw new Exception("OuterMessageScheduler CustomRouteType session does not have an routeComponent component");}if (!routeComponent.TryGetRouteId(routeType, out var routeId)){throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}");}NetworkMessagingComponent.SendInnerRoute(routeId, messageType, packInfo);}finally{if (packInfo.PackInfoId == packInfoPackInfoId){packInfo.Dispose();}}return;}case OpCodeType.OuterCustomRouteRequest:{var packInfoProtocolCode = packInfo.ProtocolCode;var packInfoPackInfoId = packInfo.PackInfoId;try{if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType)){throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode);if (messageType == null){throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}");}var routeComponent = session.GetComponent<RouteComponent>();if (routeComponent == null){throw new Exception("OuterMessageScheduler CustomRouteType session does not have an routeComponent component");}if (!routeComponent.TryGetRouteId(routeType, out var routeId)){throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}");}var rpcId = packInfo.RpcId;var runtimeId = session.RunTimeId;var response = await NetworkMessagingComponent.CallInnerRoute(routeId, messageType, packInfo);// session可能已经断开了,所以这里需要判断if (session.RunTimeId == runtimeId){session.Send(response, rpcId);}}finally{if (packInfo.PackInfoId == packInfoPackInfoId){packInfo.Dispose();}}return;}default:{packInfo.Dispose();throw new NotSupportedException($"OuterMessageScheduler Received unsupported message protocolCode:{packInfo.ProtocolCode}");}}}}

七、进入MessageHandler进行处理

调用的地方: 可以看出是没有await的

MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode);

Fantasy.Net\Runtime\Core\Network\Message\Dispatcher\MessageDispatcherComponent.cs:287

        public void MessageHandler(Session session, Type type, object message, uint rpcId, uint protocolCode){
#if FANTASY_UNITYif(_messageDelegateHandlers.TryGetValue(type,out var messageDelegateHandler)){messageDelegateHandler.Handle(session, message);return;}
#endifif (!_messageHandlers.TryGetValue(type, out var messageHandler)){Log.Warning($"Scene:{session.Scene.Id} Found Unhandled Message: {message.GetType()}");return;}// 调用消息处理器的Handle方法并启动协程执行处理逻辑messageHandler.Handle(session, rpcId, protocolCode, message).Coroutine();}

八、处理完毕后,会进行消息发送

Fantasy.Net\Runtime\Core\Network\Message\Dispatcher\Interface\IMessageHandler.cs:97

public async FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message){if (message is not TRequest request){Log.Error($"消息类型转换错误: {message.GetType().Name} to {typeof(TRequest).Name}");return;}var response = new TResponse();var isReply = false;void Reply(){if (isReply){return;}isReply = true;if (session.IsDisposed){return;}session.Send(response, rpcId);}try{await Run(session, request, response, Reply);}catch (Exception e){Log.Error(e);response.ErrorCode = InnerErrorCode.ErrRpcFail;}finally{Reply();}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/480695.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot340“共享书角”图书借还管理系统(论文+源码)_kaic

摘 要 随着社会的发展&#xff0c;图书借还的管理形势越来越严峻。越来越多的借阅者利用互联网获得信息&#xff0c;但图书借还信息量大。为了方便借阅者更好的获得本图书借还信息&#xff0c;因此&#xff0c;设计一种安全高效的“共享书角”图书借还管理系统极为重要。 为…

爬虫笔记24——纷玩岛自动抢票脚本笔记

纷玩岛自动抢票&#xff0c;协议抢票思路实现 一、获取Authorization凭证二、几个关键的参数三、几个关键的接口获取参数v&#xff0c;这个参数其实可以写死&#xff0c;可忽略通过价位获取演出的参数信息获取观演人信息&#xff0c;账号提前录入即可提交订单接口 先看实现图&a…

配置泛微e9后端开发环境

配置泛微e9的后端开发环境 1.安装jdk1.8&#xff08;请自行安装并设置环境变量&#xff09; 2.将服务器上的WEARVER文件夹拷贝到开发环境下(其中要包含ecology和Resin目录) 3.通过idea创建一个基础Java项目,将jdk设置为1.8 4.添加依赖,需要将3个文件夹的所有jar包添加到项目中…

52-基于单片机的超声波、温湿度、光照检测分阶段报警

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 1.通过DHT11模块读取环境温度和湿度: 2.将湿度、障碍物距显示在lcd1602上面&#xff0c;第一行显示温度和湿度,格式为:xxCyy%&#xff0c;第二行显示超声波传感器测得的距离&#xff0c;格式为:Di…

C++类的自动转换和强制类型转换

目录 一、类型转换 二、转换函数 一、类型转换 C⽀持内置类型隐式类型转换为类类型对象&#xff0c;需要有相关内置类型为参数的构造函数 简单说就是可以将内置类型转化为自定义类型 示例&#xff1a; class Test { public:Test(int n1 0):num1(n1){}void pr…

w~视觉~合集26

我自己的原文哦~ https://blog.51cto.com/whaosoft/12663170 #InternVL 本文设计了一个大规模的视觉-语言基础模型&#xff08;InternVL&#xff09;&#xff0c;将视觉基础模型的参数扩展到60亿&#xff0c;并逐步与LLM对齐&#xff0c;利用来自不同来源的网络规模的图像-文…

C++优选算法十六 BFS解决最短路问题

1.BFS解决最短路问题的优势与局限 BFS是一种有效的解决最短路问题的算法&#xff0c;特别适用于无权图或边权相等的图。 优势&#xff1a; BFS能够逐层遍历图中的所有节点&#xff0c;直到找到目标节点或遍历完所有可达节点。对于无权图&#xff08;即边权为1的图&#xff0…

服务器创建容器时报错: no main manifest attribute

1.出现问题的原因 springboot项目快速搭建完成以后&#xff0c;打包 > 制作容器 > 启动 在创建完成docker容器以后,启动时出现以下问题 查询了一下百度,说的是没有main文件信息, 2.解决方法 在pom文件里面加入以下代码即可 <plugins><plugin><groupI…

【小白学机器学习34】基础统计2种方法:用numpy的方法np().mean()等进行统计,pd.DataFrame.groupby() 分组统计

目录 1 用 numpy 快速求数组的各种统计量&#xff1a;mean, var, std 1.1 数据准备 1.2 直接用np的公式求解 1.3 注意问题 1.4 用print() 输出内容&#xff0c;显示效果 2 为了验证公式的背后的理解&#xff0c;下面是详细的展开公式的求法 2.1 均值mean的详细 2.2 方差…

无需插件,如何以二维码网址直抵3D互动新世界?

随着Web技术的飞速发展&#xff0c;一个无需额外插件&#xff0c;仅凭二维码或网址即可直接访问的三维互动时代已经悄然来临。这一变革&#xff0c;得益于WebGL技术与先进web3D引擎的完美融合&#xff0c;它们共同构建了51建模网这样一个既便捷又高效的在线三维互动平台&#x…

【前端】跨域问题与缓存

报错如下&#xff1a; 原因&#xff1a; 浏览器 缓存跨域&#xff0c;顾名思义是由于浏览器的缓存机制导致的一种跨域情况。这种跨域一般会出现在浏览器通过一些无视跨域的标签和css(如img、background-image)缓存了一些图片资源之后&#xff0c;当再次发起图片请求时&#xff…

怎么样才算得上熟悉高并发编程?

提到并发编程很多人就会头疼了&#xff1b;首先就是一些基础概念&#xff1a;并发&#xff0c;并行&#xff0c;同步&#xff0c;异步&#xff0c;临界区&#xff0c;阻塞&#xff0c;非阻塞还有各种锁全都砸你脸上&#xff0c;随之而来的就是要保证程序运行时关键数据在多线程…

大数据新视界 -- 大数据大厂之 Hive 数据质量保障:数据清洗与验证的策略(上)(17/ 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

MySQL5.6升级MySQL5.7

升级方式介绍 08 数据库服务版本升级方法 5.6 – 5.7 – 8.0 数据库版本升级方法&#xff1a; Inplace-本地升级 步骤一&#xff1a;在同一台服务器中&#xff0c;需要部署高版本数据库服务实例步骤二&#xff1a;低版本数据库中的数据进行备份迁移&#xff0c;迁移到高版本…

添加字符(暴力模拟)

添加字符 import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);char[] A in.next().toCharArray();char[] B in.next().toCharArray();int …

关注度上升,交易量直线上涨,Base Season 即将到来?

撰文&#xff1a;Zeneca 编译&#xff1a;Yangz&#xff0c;Techub News 译者按&#xff1a;凭借 AI 发币平台 Clanker 及 Virtuals 的爆火&#xff0c;行业对 Base 生态的关注出现「暴涨」。当地时间 11 月 26 日&#xff0c;Base 上的交易量直线拉升&#xff0c;达到约 1136…

安能物流 All in TiDB 背后的故事与成果

导读 在数字化转型的浪潮中&#xff0c;安能物流通过技术创新不断提升物流效率&#xff0c;迈出了全链路 All in TiDB 的重要一步。本文将深入探讨安能物流如何选择 TiDB 作为核心数据库&#xff0c;以应对高并发、数据处理能力和系统可扩展性等挑战。通过 TiDB 的弹性扩展能力…

《深入理解经典广度优先遍历算法》

广度优先遍历:宽度优先遍历&#xff08;Breadth-First Search, BFS&#xff09;, 图论和树论中基本的查找搜索算法&#xff0c; 是广大图算法的基础.。 前置知识和介绍 数据结构: 队列&#xff0c; 双端队列。 二叉树:经典bfs,按层bfs&#xff08;即树的层序遍历&#xff09;。…

FPGA工具链及功能介绍

一、处理流程 把verilog等源码&#xff0c;变为FPGA中可执行的比特流文件&#xff0c;主要包含这些步骤&#xff1a; 步骤功能转译将verilog代码转化为更详细的语法&#xff0c;增加更多细节内容技术映射将每个vrilog用到的模块&#xff0c;对应到FPGA的物理器件上优化优化冗余…

『python爬虫』使用docling 将pdf或html网页转为MD (保姆级图文)

目录 预览效果安装下载模型测试代码总结 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 欢迎关注 『python爬虫』 专栏&#xff0c;持续更新中 预览效果 支持转化pdf的表格 安装 Docling 本身是专注于文档转换的工具&#xff0c;通常用于将文件&#xff08;如 PDF&…