これがばかげた質問である場合は、申し訳ありませんが、私はほとんど睡眠をとっていません。
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;
}