如果这是一个愚蠢的问题,我很抱歉,我几乎没有睡觉。
我正在用 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;
}