Protobuf.ProtoException: 未找到无参数构造函数...从客户端接收特定消息时

Protobuf.ProtoException: No parameterless constructor found... when receiving specific message from client

我正在尝试使用 C# 编写异步服务器程序。我正在使用 proto-buf.net 在客户端和服务器之间发送对象。在大多数情况下,它工作正常,直到我开始使用连接到我的服务器的另一个用户测试该程序。

尝试以下操作时会出现此特定问题:

按下按钮时,将调用向所有连接到服务器的客户端发送 BattleMessage 的代码。

// in server
var message = new BattleMessage
{
  Players = players, // List<string>
  Enemies = enemies, // List<Enemy objects>
  Current = currentPlayer, // string, the current player's name
  Boss = isBoss, // boolean
  Turns = turns // string
};

收到此消息后,客户端将更改 GUI 以显示 "battle screen",其中向用户显示 BattleMessage 发送的所有信息。这样做时,它将 运行 检查显示信息的客户端名称是否匹配 "Current."

如果是,它将发回此消息:

// still in client
            if(current.Name.Equals(Current))
            {
                var message = new CurrentPlayerBattleMessage
                {
                    Name = current.Name,
                    Defense = current.GetDefense(),
                    HP = current.Hp,
                    MP = current.Mp,
                    skills = D,
                    IsPhysical = current.IsPhysical,
                };

                message.Weaknesses = weaknesses;
                Client.SendMessage(message); // send the message back to the server
            }

服务器随后将接收消息,对其进行处理并采取相应行动:

// back in the server

                // in Receive(IAsyncResult r)
                Socket client = r.AsyncState as Socket;
                client.EndReceive(r);

                // NetMessage is abstract, CurrentPlayerBattleMessage extends it
                NetMessage message = PacketManager.ProcessMessage(buffer);
                buffer = new byte[BUFFERSIZE]; // buffer: private byte[] buffer, BUFFERLENGTH = 2048
                client.BeginReceive(buffer, 0, BUFFERSIZE, SocketFlags.None, new AsyncCallback(Receive), client);

              // process after being identified
              if(message.GetType().Equals(typeof(CurrentPlayerBattleMessage)))
              {
                    var current = message as CurrentPlayerBattleMessage;

                    BattlePlayer bp = new BattlePlayer
                    {
                        Name = current.Name,
                        Defense = current.Defense,
                        HP = current.HP,
                        MP = current.MP,
                        Skills = current.Skills,
                        IsPhysical = current.IsPhysical,
                        Weaknesses = current.Weaknesses
                    };
                    //update server GUI
                    server.AddCurrentBattlePlayer(bp);
               }

当只有一个人连接到服务器时,当前玩家的技能和数据将被成功加载。当两个人连接到服务器时,会抛出问题中列出的异常。

我查看buffer是否为空的时候,听说会出现这个错误,结果竟然是这样!我不完全确定为什么,或者如何去阻止它。作为参考,在向其发送登录消息后,缓冲区将被重置。这会阻止它接收消息吗?

此外,对于上下文,这里是用于处理消息的方法:

        // both methods are used by the Client as well
        public static byte[] CreateMessage(NetMessage message)
        {
            using (var stream = new MemoryStream())
            {
                Serializer.SerializeWithLengthPrefix(stream, message, PrefixStyle.Base128);
                return stream.ToArray();
            }
        }

        public static NetMessage ProcessMessage(byte[] buffer)
        {
            using (var stream = new MemoryStream(buffer))
            {
                return Serializer.DeserializeWithLengthPrefix<NetMessage>(stream, PrefixStyle.Base128);
            }
        }

编辑:我被要求提供一些 class 信息,所以给你:

// the message causing me the issue (SERVER)
    [ProtoContract]
    public class CurrentPlayerBattleMessage : NetMessage
    {
        [ProtoMember(1)]
        public string Name { get; set; }
        [ProtoMember(2)]
        public int Defense { get; set; }
        [ProtoMember(3)]
        public int HP { get; set; }
        [ProtoMember(4)]
        public int MP { get; set; }
        [ProtoMember(5, AsReference = true)]
        public Dictionary<string, int> Skills { get; set; }
        [ProtoMember(6)]
        public bool IsPhysical { get; set; }
        [ProtoMember(7, AsReference = true)]
        public List<int> Weaknesses { get; set; }

        public CurrentPlayerBattleMessage() { }
    }

// (CLIENT)
    [ProtoContract]
    public class CurrentPlayerBattleMessage : NetMessage
    {
        [ProtoMember(1)]
        public string Name { get; set; }
        [ProtoMember(2)]
        public int Defense { get; set; }
        [ProtoMember(3)]
        public int HP { get; set; }
        [ProtoMember(4)]
        public int MP { get; set; }
        [ProtoMember(5, AsReference = true)]
        public Dictionary<string, int> skills { get; set; }
        [ProtoMember(6)]
        public bool IsPhysical { get; set; }
        [ProtoMember(7, AsReference = true)]
        public List<int> Weaknesses { get; set; }

        public CurrentPlayerBattleMessage() { }
    }

// the parent class
    [ProtoContract]
    [ProtoInclude(500, typeof(LoginMessage))]
    [ProtoInclude(501, typeof(InventoryMessage))]
    [ProtoInclude(502, typeof(BattleMessage))]
    [ProtoInclude(503, typeof(CurrentPlayerBattleMessage))]
    [ProtoInclude(504, typeof(UpdateBattleMessage))]
    [ProtoInclude(505, typeof(RewardMessage))]
    [ProtoInclude(506, typeof(RetreatMessage))]
    public abstract class NetMessage
    {
        public NetMessage() { }
    }

到目前为止 solutions/ideas 已尝试:

我通过跟踪发送的最后一条消息(一直触发错误的消息)并重新发送来解决了这个问题。每当抛出 Protobuf 异常时,程序都会假定它是由于空缓冲区造成的。

这不是最好的解决方案,事实上它非常"hacky,"但它解决了我遇到的眼前问题。