我正在关注关于使用 Photon Server 进行 MMO 开发的 Christian Richards 教程。对于那些不知道那是什么的人,它基本上涵盖了使用 MMO 类型架构从头开始重写光子框架。我遇到了许多问题,我找到了解决方法或修复方法,但这个错误我很难过。服务器启动并加载我的代理服务器和登录服务器后,我遇到以下错误。服务器启动正常,查找它很好,但是一旦它尝试注册子服务器,它就会在我的代理日志中抛出这个错误。
代理服务器日志:
2015-07-22 14:56:10,892 [1] 信息 Photon.SocketServer.ApplicationBase [(null)] 应用程序停止:AppId=Proxy
2015-07-22 14:57:01,913 [1] INFO Photon.SocketServer.ApplicationBase [(null)] - 应用程序启动:AppId=Proxy;AppPath=C:\Photon\deploy\ComplexServer,类型=ComplexServer.ComplexProxyServer
2015-07-22 14:57:01,968 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 AverageCounter: Name=''
2015-07-22 14:57:01,977 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 NumericCounter: Name=''
2015-07-22 14:57:01,986 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 CountsPerSecondCounter: Name=''
2015-07-22 14:57:01,993 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 CountsPerSecondCounter: Name=''
2015-07-22 14:57:02,001 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 NumericCounter: Name=''
2015-07-22 14:57:02,008 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 CountsPerSecondCounter: Name=''
2015-07-22 14:57:02,017 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 NumericCounter: Name=''
2015-07-22 14:57:02,026 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 CountsPerSecondCounter: Name=''
2015-07-22 14:57:02,035 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 CountsPerSecondCounter: Name=''
2015-07-22 14:57:02,043 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 NumericCounter: Name=''
2015-07-22 14:57:02,051 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 CountsPerSecondCounter: Name=''
2015-07-22 14:57:02,058 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 CountsPerSecondCounter: Name=''
2015-07-22 14:57:02,066 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 NumericCounter: Name=''
2015-07-22 14:57:02,084 [13] 调试 Photon.SocketServer.ApplicationBase [(null)] - OnInit - ConnID = 2,IP 127.0.0.1 在端口 4520,类型 = TCPListener
2015-07-22 14:57:02,108 [13] DEBUG Photon.SocketServer.Protocol [(null)] - 为应用程序 Master 解析的初始化消息,客户端版本 3.0.5,协议 GpBinaryV2 版本 1.6
2015-07-22 14:57:02,120 [11] 调试 MMO.Photon.Application.PhotonConnectionCollection [(null)] - 收到初始化请求 127.0.0.1:4520 - Photon.SocketServer.InitRequest
2015-07-22 14:57:02,127 [11] 调试 MMO.Photon.Application.PhotonApplication [(null)] - 收到来自子服务器的初始化请求
2015-07-22 14:57:02,154 [11] DEBUG Photon.SocketServer.ApplicationBase [(null)] - OnInit - 发送到 ConnId 2 的响应,SendResult Ok
2015-07-22 14:57:02,331 [7] 错误 Photon.SocketServer.ApplicationBase [(null)] - System.NotImplementedException:方法或操作未实现。在 C:\Programming\SoftwareDevelopment\C#\MMO\MMO.Photon\Application\PhotonRequest.cs 中的 MMO.Photon.Application.PhotonRequest.MMO.Framework.IMessage.get_Code():MMO.Photon.Server.PhotonServerHandlerList 的第 48 行.HandleMessage(IMessage message, PhotonServerPeer peer) in c:\Programming\SoftwareDevelopment\C#\MMO\MMO.Photon\Server\PhotonServerHandlerList.cs:MMO.Photon.Server.PhotonServerPeer.OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters) 的第 140 行在 c:\Programming\SoftwareDevelopment\C#\MMO\MMO.Photon\Server\PhotonServerPeer.cs:Photon.SocketServer.ServerToServer.ServerPeerBase.OnReceiveInternal(Byte[] 数据的第 36 行,
*如您所见,它将初始化响应/请求正确地发送到主服务器并登录,直到它尝试注册子服务器。通过观察下面的 Login.log 以及比较“注册子服务器”上的时间戳可以看出,在登录服务器尝试注册子服务器后几乎一秒钟就抛出了上述异常。
2015-07-22 14:56:10,845 [1] INFO Photon.SocketServer.ApplicationBase [(null)] - 应用程序停止:AppId=Login 2015-07-22 14:57:01,541 [12] 调试 Photon.SocketServer.ServerToServer .TemporaryServerPeer [(null)] - OnOutboundConnectionEstablished: 发送初始化请求 2015-07-22 14:57:01,541 [1] DEBUG MMO.Photon.Application.PhotonApplication [(null)] - 在 127.0.0.1:4520 2015 连接到 master -07-22 14:57:01,584 [1] INFO Photon.SocketServer.ApplicationBase [(null)] - 应用程序启动:AppId=Login;AppPath=C:\Photon\deploy\ComplexServer,类型=LoginServer.LoginServer 2015-07-22 14:57:01,592 [12] 调试 Photon.SocketServer.ServerToServer.TemporaryServerPeer [(null)] - SentInitRequest: ConnID=2, ChannelId =0,结果=确定大小=41 字节 2015-07-22 14:57:02,157 [13] 调试 ExitGames.Diagnostics.Counter.CounterBase [(null)] - 创建 AverageCounter:
以下代码来自我认为相关的类。
PhotonRequest 类:
class PhotonRequest : IMessage
{
private readonly byte _code;
private readonly Dictionary<byte, object> _parameters;
private readonly int? _subCode;
public PhotonRequest(byte code, int? subCode, Dictionary<byte, object> parameters)
{
_code = code;
_parameters = parameters;
_subCode = subCode;
}
public short Code
{
get { return _code; }
}
public MessageType Type
{
get { return MessageType.Response; }
}
public int? SubCode
{
get { return _subCode; }
}
public Dictionary<byte, object> Parameters
{
get { return _parameters; }
}
byte IMessage.Code
{
get { throw new NotImplementedException(); }
}
}
PhotonServerHandlerList 类:
public class PhotonServerHandlerList
{
private readonly DefaultRequestHandler _defaultRequestHandler;
private readonly DefaultResponseHandler _defaultResponseHandler;
private DefaultEventHandler _defaultEventHandler;
protected readonly ILogger Log;
private readonly Dictionary<int, PhotonServerHandler> _requestHandlerList;
private readonly Dictionary<int, PhotonServerHandler> _responseHandlerList;
private readonly Dictionary<int, PhotonServerHandler> _eventHandlerList;
public PhotonServerHandlerList(IEnumerable<IHandler<PhotonServerPeer>> handlers,
DefaultRequestHandler defaultRequestHandler, DefaultResponseHandler defaultResponseHandler,
DefaultEventHandler defaultEventHandler, PhotonApplication application)
{
_defaultRequestHandler = defaultRequestHandler;
_defaultResponseHandler = defaultResponseHandler;
_defaultEventHandler = defaultEventHandler;
Log = application.Log;
_requestHandlerList = new Dictionary<int, PhotonServerHandler>();
_responseHandlerList = new Dictionary<int, PhotonServerHandler>();
_eventHandlerList = new Dictionary<int, PhotonServerHandler>();
foreach (PhotonServerHandler handler in handlers)
{
if(!RegisterHandler(handler))
{
Log.WarnFormat("attempted to register handler {0} for type{1}|{2}", handler.GetType().Name, handler.Type, handler.Code);
}
}
}
public bool RegisterHandler(PhotonServerHandler handler)
{
var registered = false;
if((handler.Type & MessageType.Request) == MessageType.Request)
{
if (handler.SubCode.HasValue && !_requestHandlerList.ContainsKey(handler.SubCode.Value))
{
_requestHandlerList.Add(handler.SubCode.Value, handler);
registered = true;
}
else if (!_requestHandlerList.ContainsKey(handler.Code))
{
_requestHandlerList.Add(handler.Code, handler);
registered = true;
}
else
{
Log.ErrorFormat("RequestHandler list already contains handler for {0} - cannot add {1}", handler.Code, handler.GetType().Name);
}
}
if ((handler.Type & MessageType.Response) == MessageType.Response)
{
if (handler.SubCode.HasValue && !_responseHandlerList.ContainsKey(handler.SubCode.Value))
{
_responseHandlerList.Add(handler.SubCode.Value, handler);
registered = true;
}
else if (!_responseHandlerList.ContainsKey(handler.Code))
{
_responseHandlerList.Add(handler.Code, handler);
registered = true;
}
else
{
Log.ErrorFormat("Response Handler list already contains handler for {0} - cannot add {1}", handler.Code, handler.GetType().Name);
}
}
if ((handler.Type & MessageType.Async) == MessageType.Async)
{
if (handler.SubCode.HasValue && !_eventHandlerList.ContainsKey(handler.SubCode.Value))
{
_eventHandlerList.Add(handler.SubCode.Value, handler);
registered = true;
}
else if (!_eventHandlerList.ContainsKey(handler.Code))
{
_eventHandlerList.Add(handler.Code, handler);
registered = true;
}
else
{
Log.ErrorFormat("event Handler list already contains handler for {0} - cannot add {1}", handler.Code, handler.GetType().Name);
}
}
return registered;
}
public bool HandleMessage(IMessage message, PhotonServerPeer peer)
{
bool handled = false;
switch (message.Type)
{
case MessageType.Request:
if (message.SubCode.HasValue && _requestHandlerList.ContainsKey(message.SubCode.Value))
{
_requestHandlerList[message.SubCode.Value].HandleMessage(message, peer);
handled = true;
}
else if (!message.SubCode.HasValue && _requestHandlerList.ContainsKey(message.Code))
{
_requestHandlerList[message.Code].HandleMessage(message, peer);
handled = true;
}
else
{
_defaultRequestHandler.HandleMessage(message, peer);
}
break;
case MessageType.Response:
if (message.SubCode.HasValue && _responseHandlerList.ContainsKey(message.SubCode.Value))
{
_responseHandlerList[message.SubCode.Value].HandleMessage(message, peer);
handled = true;
}
else if (!message.SubCode.HasValue && _responseHandlerList.ContainsKey(message.Code))
{
_responseHandlerList[message.Code].HandleMessage(message, peer);
handled = true;
}
else
{
_defaultResponseHandler.HandleMessage(message, peer);
}
break;
case MessageType.Async:
if (message.SubCode.HasValue && _eventHandlerList.ContainsKey(message.SubCode.Value))
{
_eventHandlerList[message.SubCode.Value].HandleMessage(message, peer);
handled = true;
}
else if (!message.SubCode.HasValue && _eventHandlerList.ContainsKey(message.Code))
{
_eventHandlerList[message.Code].HandleMessage(message, peer);
handled = true;
}
else
{
_defaultEventHandler.HandleMessage(message, peer);
}
break;
}
return handled;
}
}
消息界面:
public interface IMessage
{
MessageType Type { get; }
byte Code { get; }
int? SubCode { get; } // nullable int
Dictionary<byte, object> Parameters { get; }
}