2

如果这是一个愚蠢的问题,我很抱歉,我几乎没有睡觉。

我正在用 C++ 序列化协议缓冲区消息,并通过 TCP 连接将其发送到 C# 客户端。一切工作大约 75% 的时间,但是,大约 25% 的时间,我得到一个无效的序列化异常。

经过一番摸索,我发现来自有效消息的字节数组与无效消息不同。它似乎始终是相同的字节,这是错误的。

如有必要,我可以发布代码,但我在这里遗漏了什么吗?为什么 C++ 服务器不会每次都以相同的方式序列化一个对象?(顺便说一句,我硬编码了一个对象来测试它。为了确保字段没有改变。)

从客户端的角度来看,这是通过套接字发送后的字节数组。

8 162 1 18 21 84 87 32 86 101 110 100 105 110 103 32 68 101 109 111 32 83 116 111 114 101 24 176 32 132 131 186 141 5 40 2 48 42 56 2 - bad serialization

8 162 1 18 21 84 87 32 86 101 110 100 105 110 103 32 68 101 109 111 32 83 116 111 114 101 24   7 32 132 131 186 141 5 40 2 48 42 56 2 - good serialization

8 162 1 18 21 84 87 32 86 101 110 100 105 110 103 32 68 101 109 111 32 83 116 111 114 101 24 128 32 132 131 186 141 5 40 2 48 42 56 2 - bad serialization

8 162 1 18 21 84 87 32 86 101 110 100 105 110 103 32 68 101 109 111 32 83 116 111 114 101 24 216 32 132 131 186 141 5 40 2 48 42 56 2 - bad serialization

8 162 1 18 21 84 87 32 86 101 110 100 105 110 103 32 68 101 109 111 32 83 116 111 114 101 24   0 32 132 131 186 141 5 40 2 48 42 56 2 - good serialization

8 162 1 18 21 84 87 32 86 101 110 100 105 110 103 32 68 101 109 111 32 83 116 111 114 101 24 255 32 132 131 186 141 5 40 2 48 42 56 2 - bad serialization

注意最后的第 13 个字节是不同的吗?我还添加了成功序列化的那些。谢谢。

更新 - 我发布了我的 C# 客户端代码,因为问题很可能出在这一端。我还包装了生成的 proto 对象,因此您必须相信我的序列化功能正常工作。(我 100% 确定他们是。)

 private List<byte> LockNetworkStream(ref System.IO.Stream clientStream, byte[] data)
        {
            List<byte> completeMessage = new List<byte>();

            try
            {
                lock (clientStream)
                {
                    byte[] bufferLength = BitConverter.GetBytes(data.Length);
                    clientStream.ReadTimeout = 10000;

                    clientStream.Write(bufferLength, 0, bufferLength.Length);
                    clientStream.Flush();

                    clientStream.Write(data, 0, data.Length);
                    clientStream.Flush();

                    byte[] messageLength = new byte[4];
                    int bytesRead = 0;

                    bytesRead = clientStream.Read(messageLength, 0, 4);
                    int messageSize = BitConverter.ToInt32(messageLength, 0);
                    if (messageSize > 0)
                    {
                        int totalBytesRead = 0;
                        byte[] message = new byte[messageSize];                        
                        while (totalBytesRead < messageSize)
                        {
                            bytesRead = clientStream.Read(message, 0, messageSize - totalBytesRead);
                            if (bytesRead > 0)
                            {
                                byte[] temp = new byte[bytesRead];
                                for (int i = 0; i < bytesRead; i++)
                                {
                                    temp[i] = message[i];
                                }

                                completeMessage.AddRange(temp);
                                totalBytesRead += bytesRead;
                            }
                            else
                            {
                                break;
                            }
                        }

                        clientStream.Flush();
                    }
                }  
            }
            catch (StokedTcpException ex)
            {
                throw ex;
            }
            catch (InvalidOperationException ex)
            {
                if (reconnectAttempts < 3)
                {
                    Reconnect();
                    return LockNetworkStream(ref clientStream, data);   
                }
                else
                {
                    throw new Exception("Unable to connect.  Please check your internet connection or firewall config");
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return completeMessage;
        }

        public byte[] Communicate(byte[] data, ref TcpClient client)
        {
            byte[] bufferLength = BitConverter.GetBytes(data.Length);
            System.IO.Stream clientStream = null;
            lock (client)
            {
                clientStream = client.GetStream();
            }            

            List<byte> completeMessage = LockNetworkStream(ref clientStream, data);

            ServerFunctionResponse response = null;
            try
            {
                response = ServerFunctionResponse.Deserialize(completeMessage.ToArray());
                deserializeAttempts = 0;
            }
            catch (Exception ex)
            {

                throw new Exception("Unable to deserialize server response: " + ex.Message);
            }

            if (response.IsException)
            {
                StokedTcpException exception = StokedTcpException.Deserialize(response.Data);
                throw exception;
            }

            return response.Data;            
        }
4

0 回答 0