Unity游戏开发Photon Server之服务端架构

发表于2017-08-31
评论0 4.6k浏览
首先,服务端分两大部分,第一部分是服务端和客户端都需要使用的部分,第二部分就是接收客户端请求并发送数据的逻辑处理部分,也就是服务端架构了;

一、服务端和客户端通用部分

我们建立一个类库项目,将服务端和客户端需要进行通讯的数据类型存储在这里,包括操作代码(OperationCode),参数的增加和提取(ParameterTool.GetParameter和ParameterTool.AddParameter),以及参数的代码(ParameterCode)等。此外,数据库中的数据类型(DBModel(这里面的类是用来检索暂时存储数据库中的数据的))也放在这里。ParameterTool中的类如下:
 public class ParameterTool {
        public static T GetParameter<T>(Dictionary<byte,object> parameters,ParameterCode parameterCode ,bool isObject = true)
        {
            object o = null;
            parameters.TryGetValue((byte) parameterCode, out o);
            if (isObject==false)
            {
                return (T) o;
            }
            return JsonMapper.ToObject<T>(o.ToString());
        }
        public static void AddParameter<T>(Dictionary<byte, object> parameters, ParameterCode key, T value,
            bool isObject = true)
        {
            if (isObject)
            {
                string json = JsonMapper.ToJson(value);
                parameters.Add((byte) key, json);
            }
            else
            {
                parameters.Add((byte) key, value);
            }
        }
        public static SubCode GetSubcode(Dictionary<byte, object> parameters)
        {
            return GetParameter<SubCode>(parameters, ParameterCode.SubCode, false);
        }
        public static void AddSubcode(Dictionary<byte, object> parameters, SubCode subcode)
        {
            AddParameter<SubCode>(parameters,ParameterCode.SubCode, subcode,false);
        }
        public static void AddOperationcodeSubcodeRoleID(Dictionary<byte, object> parameters, OperationCode opCode, int roleID)
        {
            if(parameters.ContainsKey((byte) ParameterCode.OperationCode))
            {
                parameters.Remove((byte) ParameterCode.OperationCode);
            }
            if(parameters.ContainsKey((byte) ParameterCode.RoleID))
            {
                parameters.Remove((byte) ParameterCode.RoleID);
            }
            parameters.Add((byte)ParameterCode.OperationCode, opCode);
            parameters.Add((byte)ParameterCode.RoleID, roleID);
        }
    }

Model中是和数据库中表对应的类,除开一个工具类之外,其它的都是枚举类型。暂时所用到的结构就是这样。总结一下就是:Models,Tools,OperationOfCodes。

二、服务端架构

服务端有一个继承了ApplicationBase的ArpgApplication类,还有一个继承了PeerBase的ClientPeer.服务端接收到了连接的请求后会创建ClientPeer,接受Request和发送Response的函数都在ClientPeer中。

主要结构如下图:

此结构中所有的Handler与客户端的各个Controller对应,一个Controller对应一个Handler,他们之间处理相应的Request和Response.在服务端调用的时候,先是ClientPeer接收到Request,然后根据OperationCode,判断该调用哪个Handler,在ArpgApplication中找到对应的Handler,然后把Request发给它让它进行处理,返回处理的结果Response,发送给客户端。

在Handler处理的过程中,一般都会需要对数据库进行操作,所有的操作都封装在DB.Manager中,对相应的数据库操作调用相应的的Manager中的方法即可。

附上继承自ApplicationBase类的代码示例:
 public class ARApplication : ApplicationBase
    {
        public List<ARPeer> peerListForTeam = new List<ARPeer>();
        public Dictionary<byte, HandlerBase> handlers = new Dictionary<byte, HandlerBase>();
        private static ARApplication _instance;
        private static readonly ILogger log = ExitGames.Logging.LogManager.GetCurrentClassLogger();
        public ARApplication()
        {
            _instance = this;
            RegisterHandler();
        }
        public static ARApplication AR_Instance
        {
            get {
                return _instance;
            }
        }
        void RegisterHandler()
        {
            //handlers.Add((byte)OperationCode.Login,new LoginHandler());
            //handlers.Add((byte)OperationCode.MakeRoom,new MakeRoomHandler());
            Type[] types = Assembly.GetAssembly(typeof(HandlerBase)).GetTypes();   //得到所有继承自HandlerBase的类
            foreach (var type in types)
            {
                if (type.FullName.EndsWith("Handler"))
                {
                    Activator.CreateInstance(type);    //创建类的实例,为了能够使各个Handler的构造函数实现在ARApplication中注册
                }
            }
        }
        protected override PeerBase CreatePeer(InitRequest initRequest)
        {
            return new ARPeer(initRequest.Protocol,initRequest.PhotonPeer);
        }
        protected override void Setup()
        {
            ExitGames.Logging.LogManager.SetLoggerFactory(Log4NetLoggerFactory.Instance);
            GlobalContext.Properties["Photon:ApplicationLogPath"] = Path.Combine(this.ApplicationRootPath, "log");
            GlobalContext.Properties["LogFileName"] = "MS" + this.ApplicationName;
            XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(this.BinaryPath, "log4net.config")));
            log.Debug("ARServer is Setup!!!");
        }
        protected override void TearDown()
        {
            log.Debug("ARServer is TearDown!!!");
        }
    }

接着看继承自PeerBase类的实例:
protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
        {
            HandlerBase handler;
            ARApplication.AR_Instance.handlers.TryGetValue(operationRequest.OperationCode, out handler);
            if (handler != null)
            {
                OperationResponse response = new OperationResponse();
                response.OperationCode = operationRequest.OperationCode;
                response.Parameters = new Dictionary<byte, object>();
                handler.OnHandlerMessage(operationRequest, response, this,sendParameters);
                SendOperationResponse(response, sendParameters);
            }
            else
            {
                //ARApplication的字典Handlers中没有operationRequest.OperationCode对应的Handler;
            }
        }

抽象的基类HandlerBase中的代码示例如下(各种Handler继承自HandlerBase并实现重写其中的抽象方法):
  public abstract class HandlerBase
    {
        private static readonly ILogger log = ExitGames.Logging.LogManager.GetCurrentClassLogger();
        public HandlerBase()
        {
            ARApplication.AR_Instance.handlers.Add((byte)opCode, this); //在Application类中注册各种Handler
            log.Debug("Hanlder:" + this.GetType().Name + "  is register.");
        }
        public abstract void OnHandlerMessage(OperationRequest request,OperationResponse response, ARPeer peer, SendParameters sendParameters);
        public abstract OperationCode opCode
        {
            get;
        }
    }

大致就像下图:

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引