分布式服务器框架之Server.Common中通过Xml配置渠道、服务器集群、热更新信息代码解析Xml缓存进内存

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
全局流量管理 GTM,标准版 1个月
简介: ChannelConfig.cs代码解析加载ChannelConfig.xml。使用了System.Xml.Linq的XDocument工具类来加载xml文件。其基本原理就是获取到Root节点下名为“Channel”的所有Element节点,然后使用迭代器循环,拿到每一个Element中的属性,先缓存ChannelEntity结构中,最后存到字典里。

服务器的配置分了三个文件:分别是ChannelConfig.xml、HotFixConfig.xml、ServerConfig.xml。


ChannelConfig.xml 标签中的属性        


ChannelId:            渠道Id


InnerVersion:        内部版本号


SourceVersion:     该渠道当前的资源版本号(根据当前的资源版本号和资源地址拼接出一个绝对路径)


SourceUrl:            资源站点的Ip和端口


RechargeUrl:        充值服务器的地址


PayServerNo:       充值服务器编号


TDAppId:              统计平台编号


IsOpenTD:            是否开启统计


Xml配置


<?xml version="1.0" encoding="utf-8" ?>
<Root>
  <Channel ChannelId="0" InnerVersion="1001" SourceVersion="1.0.7" SourceUrl="http://127.0.0.1:8090" RechargeUrl="http://127.0.0.1" PayServerNo="" TDAppId="" IsOpenTD="" />
</Root>


ChannelConfig.cs代码解析加载ChannelConfig.xml。使用了System.Xml.Linq的XDocument工具类来加载xml文件。其基本原理就是获取到Root节点下名为“Channel”的所有Element节点,然后使用迭代器循环,拿到每一个Element中的属性,先缓存ChannelEntity结构中,最后存到字典里。


namespace Servers.Common
{
    public class ChannelConfig
    {
        public static Dictionary<string, ChannelEntity> m_dicChannel;
        //渠道数据初始化
        public static void Init()
        {
            m_dicChannel = new Dictionary<string, ChannelEntity>();
            string path = AppDomain.CurrentDomain.BaseDirectory + "Configs/ChannelConfig.xml";
            ChannelEntity entity;
            XDocument doc = XDocument.Load(path);
            XElement item;
            IEnumerator<XElement> iter = doc.Root.Elements("Channel").GetEnumerator();
            for (; iter.MoveNext();)
            {
                item = iter.Current;
                entity = new ChannelEntity();
                int.TryParse(item.Attribute("ChannelId").Value,out entity.ChannelId);
                int.TryParse(item.Attribute("InnerVersion").Value,out entity.InnerVersion);
                entity.SourceVersion = item.Attribute("SourceVersion").Value;
                entity.SourceUrl = item.Attribute("SourceUrl").Value;
                entity.RechargeUrl = item.Attribute("RechargeUrl").Value;
                int.TryParse(item.Attribute("PayServerNo").Value, out entity.InnerVersion);
                entity.TDAppId = item.Attribute("TDAppId").Value;
                bool.TryParse(item.Attribute("IsOpenTD").Value,out entity.IsOpenTD);
                //频道Id_内部版本
                m_dicChannel[entity.ChannelId + "_" + entity.InnerVersion] = entity;
            }
            Console.WriteLine(" ChannelConfig Load Complete");
        }
    }
}


HotFixConfig.xml中的属性

Key:Dll名字

Value:Dll文件

Xml配置。热更新dll名称配置表格的原因是每次加载的时候都需要把名字往后+1,C#不允许加载相同名字的Dll


<?xml version="1.0" encoding="utf-8" ?>
<Root> 
  <Item  Key="HotFixAssemblyName"  Value="Servers.HotFix.dll"/>
</Root>


HotFixConfig.cs代码解析加载HotFixConfig.xml。


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
namespace Servers.Common
{
    //可以热更新的配置文件
    public class HotFixConfig
    {
        private static Dictionary<string, string> m_dicParams;
        //根据Key获取参数
        public static string GetParams(string key)
        {
            string value = null;
            m_dicParams.TryGetValue(key,out value);
            return value;
        }
        //加载热更新dll参数
        public static void Load()
        {
            //有可能会重复Load,所以每次Load需要Clear操作
            if (null == m_dicParams)
                m_dicParams = new Dictionary<string, string>();
            else 
                m_dicParams.Clear();
            //cs工程目录+Configs目录,拼接出来一个绝对目录
            string path = AppDomain.CurrentDomain.BaseDirectory + "Configs/HotFixConfig.xml";
            XElement item;
            XDocument doc = XDocument.Load(path);
            IEnumerator<XElement> iter = doc.Root.Elements("Item").GetEnumerator();
            for (; iter.MoveNext();)
            {
                item = iter.Current;
                string key = item.Attribute("Key").Value;
                string value = item.Attribute("Value").Value;
                m_dicParams[key] = value;
            }
            Console.WriteLine(" HotFixConfig Load Complete");
        }
    }
}


ServerConfig.xml 标签中的属性  


AreaServerId:                   区服编号      


CurrServerType:               当前服务器类型


CurrServerId:                    当前服务器编号


MongoConnectString:     MongoDB连接字符串


RedisConnectString:       Redis连接字符串


DataTablePath:                 数据表路径


Servers:                             服务器配置


Xml配置,这个是按照单服的结构设计的xml,如果以后有多服了,得把Servers、DB、Redis都得移到AreaServer里面去,外面套一层结构


<?xml version="1.0" encoding="utf-8" ?>
<Root>
  <AreaServerId>1</AreaServerId>
  <CurrServerType>0</CurrServerType>
  <CurrServerId>0</CurrServerId>
  <MongoConnectString>mongodb://127.0.0.1</MongoConnectString>
  <RedisConnectString>127.0.0.1:6379</RedisConnectString>
  <DataTablePath>C:\game\Server\Release\DataTable</DataTablePath>
  <Servers>
    <!--中心(世界)服务器-->>
    <Item ServerType="0" ServerId="1" Ip="10.0.24.10" Port="1301"/>
    <!--游戏服务器1-->>
    <Item ServerType="1" ServerId="1" Ip="10.0.24.10" Port="1302"/>
    <!--游戏服务器2-->>
    <Item ServerType="1" ServerId="2" Ip="10.0.24.10" Port="1303"/>
    <!--网关服务器1-->>
    <Item ServerType="2" ServerId="1" Ip="10.0.24.10" Port="1304"/>
    <!--网关服务器2-->>
    <Item ServerType="2" ServerId="2" Ip="10.0.24.10" Port="1305"/>
  </Servers>
  <Scenes>
    <!--这些json是啥?到时候写到寻路服务器的时候再看看吧!-->>
    <Item SceneId="1" ServerId="1" AOIJsonDataPath="" />
    <Item SceneId="2" ServerId="1" AOIJsonDataPath="" />
    <Item SceneId="3" ServerId="2" AOIJsonDataPath="" />
    <Item SceneId="4" ServerId="2" AOIJsonDataPath="" />
    <Item SceneId="5" ServerId="2" AOIJsonDataPath="" />
    <Item SceneId="6" ServerId="2" AOIJsonDataPath="" />
    <Item SceneId="7" ServerId="2" AOIJsonDataPath="" />
    <Item SceneId="8" ServerId="2" AOIJsonDataPath="" />
  </Scenes>
</Root>


ServerConfig.cs代码解析加载ServerConfig.xml。SceneConfig结构存的是哪些服务器应该为哪些场景提供服务器的信息,一个服务器可能算量有限并不能为整个大区的提供计算,将场景为单位把玩家划分到了不同的服务器上进行计算。Server类存的是单个服务器的配置,这个服务器需要开启的场景列表信息。ServerConfig则是有点像是传统的Manager类,会记录所有的Server信息到map结构里。


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Linq;
using Servers.Core;
namespace Servers.Common
{
    public class SceneConfig
    {
        //场景编号
        public int SceneId;
        //服务器编号
        public int ServerId;
        //AOI区域数据路径
        public string AOIJsonDataPath;
    }
    //单台服务器配置
    public class Server
    {
        //服务器类型
        public ConstDefine.ServerType CurrServerType;
        //服务器编号
        public int ServerId;
        //服务器Ip
        public string Ip;
        //服务器端口
        public int Port;
        //这个服务器需要开启的场景列表(这个服务器为特定的一些场景提供服务,跳转场景则切另一个服务器为玩家服务)
        public List<SceneConfig> SceneConfigs { get; }
        public Server()
        {
            SceneConfigs = new List<SceneConfig>(100);
        }
    }
    public class ServerConfig
    {
        #region 静态成员
        //区服编号
        public static int AreaServerId;
        //当前服务器类型
        public static ConstDefine.ServerType CurrServerType;
        //当前服务器编号
        public static int CurrServerId = 0;
        //Mongo连接字符串
        public static string MongoConnectionString;
        //Redis连接字符串
        public static string RedisConnectionString;
        //数据表路径
        public static string DataTablePath;
        //区服内服务器列表
        private static List<Server> ServerList;
        //场景和游戏服务器的对应字典(哪个场景在哪个服务器上运算 SceneId:SceneConfig)
        public static Dictionary<int,SceneConfig> DicSceneInServer;
        //游戏服务DB名(一个区服务,一个DB??一个区服如果只使用一个DB,很多个服务同时像这一个DB写数据的话不会造成拥堵吗??)
        private static string m_GameServerDBName = null;
        public static string GameServerDBName
        {
            get
            {
                if (string.IsNullOrEmpty(m_GameServerDBName))
                    m_GameServerDBName = string.Format("GameServer_{0}", AreaServerId);
                return m_GameServerDBName;
            }
        }
        //角色HashKey(就是个Key,看代码好像是一个区服只能有一个Role啊,目前没看到哪里用)
        private static string m_RoleHashKey = null;
        private static string RoleHashKey
        {
            get
            {
                if (string.IsNullOrEmpty(m_RoleHashKey))
                    m_RoleHashKey = string.Format("{0}_RoleHash", AreaServerId);
                return m_RoleHashKey;
            }
        }
        //角色昵称Key(玩家名称)
        private static string m_RoleNickNameKey = null;
        public static string RoleNickNameKey
        {
            get 
            {
                if (string.IsNullOrEmpty(m_RoleNickNameKey))
                    m_RoleNickNameKey = string.Format("{0}_NickName", AreaServerId);
                return m_RoleNickNameKey;
            }
        }
        public static void Init()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory + "Configs/ServerConfig.xml";
            XDocument doc = XDocument.Load(path);
            XElement itemRoot = doc.Root;
            AreaServerId = itemRoot.Element("AreaServerId").Value.ToInt();
            CurrServerType = (ConstDefine.ServerType)itemRoot.Element("CurrServerType").Value.ToInt();
            CurrServerId = itemRoot.Element("CurrServerId").Value.ToInt();
            MongoConnectionString  = itemRoot.Element("MongoConnectString").Value;
            RedisConnectionString = itemRoot.Element("RedisConnectString").Value;
            DataTablePath = itemRoot.Element("DataTablePath").Value;
            ServerList = new List<Server>();
            DicSceneInServer = new Dictionary<int, SceneConfig>();
            //初始化服务器节点
            XElement itemServer;
            IEnumerator<XElement> iterServer = itemRoot.Element("Servers").Elements("Item").GetEnumerator();
            for (; iterServer.MoveNext();)
            {
                itemServer = iterServer.Current;
                ServerList.Add(new Server()
                {
                    CurrServerType = (ConstDefine.ServerType)itemServer.Attribute("ServerType").Value.ToInt(),
                    ServerId = itemServer.Attribute("ServerId").Value.ToInt(),
                    Ip = itemServer.Attribute("Ip").Value,
                    Port = itemServer.Attribute("Port").Value.ToInt()
                }) ;
            }
            //初始化场景对应的服务器
            XElement itemScene;
            SceneConfig sceneCfg;
            Server server;
            int sceneId;
            int serverId;
            string aoiJsonDataPath;
            IEnumerator<XElement> iterScene = itemRoot.Element("Scenes").Elements("Item").GetEnumerator();
            for (; iterScene.MoveNext();)
            {
                itemScene = iterScene.Current;
                sceneId = itemScene.Attribute("SceneId").Value.ToInt();
                serverId = itemScene.Attribute("ServerId").Value.ToInt();
                aoiJsonDataPath = itemScene.Attribute("AOIJsonDataPath").Value;
                sceneCfg = new SceneConfig()
                {
                    SceneId = sceneId,
                    ServerId = serverId,
                    AOIJsonDataPath = aoiJsonDataPath
                };
                //保存场景对应的服务器
                DicSceneInServer[sceneId] = sceneCfg;
                //获取对应的服务器,正向写入该服务器会服务哪些场景
                server = GetServer(ConstDefine.ServerType.GameServer, serverId);
                if (null != server)
                {
                    server.SceneConfigs.Add(sceneCfg);
                }
            }
            Console.WriteLine("ServerConfig Init Complete");
        }
        public static Server GetServer(ConstDefine.ServerType type,int serverId)
        {
            int iLen = ServerList.Count;
            Server server = null;
            for (int i = 0; i < iLen; ++i)
            {
                server = ServerList[i];
                if (server.CurrServerType == type && server.ServerId == serverId)
                    return server;
            }
            return null;
        }
        #endregion
    }
}


这个笔记写完啦!

相关文章
|
26天前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
35 3
|
1月前
|
存储 缓存 算法
分布式锁服务深度解析:以Apache Flink的Checkpointing机制为例
【10月更文挑战第7天】在分布式系统中,多个进程或节点可能需要同时访问和操作共享资源。为了确保数据的一致性和系统的稳定性,我们需要一种机制来协调这些进程或节点的访问,避免并发冲突和竞态条件。分布式锁服务正是为此而生的一种解决方案。它通过在网络环境中实现锁机制,确保同一时间只有一个进程或节点能够访问和操作共享资源。
63 3
|
1月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
100 3
|
20天前
|
存储 分布式计算 负载均衡
分布式计算模型和集群计算模型的区别
【10月更文挑战第18天】分布式计算模型和集群计算模型各有特点和优势,在实际应用中需要根据具体的需求和条件选择合适的计算架构模式,以达到最佳的计算效果和性能。
44 2
|
1月前
|
消息中间件 中间件 数据库
NServiceBus:打造企业级服务总线的利器——深度解析这一面向消息中间件如何革新分布式应用开发与提升系统可靠性
【10月更文挑战第9天】NServiceBus 是一个面向消息的中间件,专为构建分布式应用程序设计,特别适用于企业级服务总线(ESB)。它通过消息队列实现服务间的解耦,提高系统的可扩展性和容错性。在 .NET 生态中,NServiceBus 提供了强大的功能,支持多种传输方式如 RabbitMQ 和 Azure Service Bus。通过异步消息传递模式,各组件可以独立运作,即使某部分出现故障也不会影响整体系统。 示例代码展示了如何使用 NServiceBus 发送和接收消息,简化了系统的设计和维护。
46 3
|
10天前
|
存储 Java 开发者
Java中的集合框架深入解析
【10月更文挑战第32天】本文旨在为读者揭开Java集合框架的神秘面纱,通过深入浅出的方式介绍其内部结构与运作机制。我们将从集合框架的设计哲学出发,探讨其如何影响我们的编程实践,并配以代码示例,展示如何在真实场景中应用这些知识。无论你是Java新手还是资深开发者,这篇文章都将为你提供新的视角和实用技巧。
11 0
|
16天前
|
存储 监控 大数据
构建高可用性ClickHouse集群:从单节点到分布式
【10月更文挑战第26天】随着业务的不断增长,单一的数据存储解决方案可能无法满足日益增加的数据处理需求。在大数据时代,数据库的性能、可扩展性和稳定性成为企业关注的重点。ClickHouse 是一个用于联机分析处理(OLAP)的列式数据库管理系统(DBMS),以其卓越的查询性能和高吞吐量而闻名。本文将从我的个人角度出发,分享如何将单节点 ClickHouse 扩展为高可用性的分布式集群,以提升系统的稳定性和可靠性。
43 0
|
1月前
|
分布式计算 Hadoop
Hadoop-27 ZooKeeper集群 集群配置启动 3台云服务器 myid集群 zoo.cfg多节点配置 分布式协调框架 Leader Follower Observer
Hadoop-27 ZooKeeper集群 集群配置启动 3台云服务器 myid集群 zoo.cfg多节点配置 分布式协调框架 Leader Follower Observer
47 1
|
30天前
|
分布式计算 Java 应用服务中间件
NettyIO框架的深度技术解析与实战
【10月更文挑战第13天】Netty是一个异步事件驱动的网络应用程序框架,由JBOSS提供,现已成为Github上的独立项目。
37 0
|
1月前
|
存储 缓存 数据处理
深度解析:Hologres分布式存储引擎设计原理及其优化策略
【10月更文挑战第9天】在大数据时代,数据的规模和复杂性不断增加,这对数据库系统提出了更高的要求。传统的单机数据库难以应对海量数据处理的需求,而分布式数据库通过水平扩展提供了更好的解决方案。阿里云推出的Hologres是一个实时交互式分析服务,它结合了OLAP(在线分析处理)与OLTP(在线事务处理)的优势,能够在大规模数据集上提供低延迟的数据查询能力。本文将深入探讨Hologres分布式存储引擎的设计原理,并介绍一些关键的优化策略。
97 0

推荐镜像

更多