Socket の TcpListener/TcpClient ラッパーを使用して作成した C# の非同期 TCP ソケット サーバーがあります。私は一般的にネットワーキングにかなり慣れていないので、TCP が送信されたデータをどのように処理するか、およびメッセージの境界をどのように保持しないかを知りませんでした。少し調査した結果、確かな解決策を思いついたと思いますが、誰か私にもっとアドバイスがあるかどうか疑問に思っています。
現在、送信しているデータは、protobuf (Google のデータ交換ライブラリ) https://code.google.com/p/protobuf/を使用してシリアル化されたクラス オブジェクトの byte[] です。
データをシリアル化した後、送信する前に、バイト配列の先頭に 4 バイトの Int32 を追加することにしました。私の考えでは、パケットがサーバーに送信されると、Int32 が解析され、そのバイト数を受信するまで待ってから、データを処理します。それ以外の場合は、BeginRead を再度呼び出すだけです。
データを書き込む前に実行したコードは次のとおりです。正常に動作しているように見えますが、パフォーマンスに関する提案は受け付けています。
public byte[] PackByteArrayForSending(byte[] data)
{
// [0-3] Packet Length
// [3-*] original data
// Get Int32 of the packet length
byte[] packetLength = BitConverter.GetBytes(data.Length);
// Allocate a new byte[] destination array the size of the original data length plus the packet length array size
byte[] dest = new byte[packetLength.Length + data.Length];
// Copy the packetLength array to the dest array
Buffer.BlockCopy(packetLength, 0, dest, 0, packetLength.Length);
// Copy the data array to the dest array
Buffer.BlockCopy(data, 0, dest, packetLength.Length, data.Length);
return dest;
}
私はサーバー側で少し立ち往生しています。Buffer.BlockCopy を使用して最初の 4 バイトをコピーし、次に BitConverter.ToInt32 を使用して取得する長さを読み取ることで、packetLength 変数を読み取らせます。着信データを常にクライアント固有の Stream オブジェクトに読み込む必要があるのか、それとも while ループを使用するだけなのかがわかりません。これまでにサーバー側にあるコードの例を次に示します。
NetworkStream networkStream = client.NetworkStream;
int bytesRead = networkStream.EndRead(ar);
if (bytesRead == 0)
{
Console.WriteLine("Got 0 bytes from {0}, marking as OFFLINE.", client.User.Username);
RemoveClient(client);
}
Console.WriteLine("Received {0} bytes.", bytesRead);
// Allocate a new byte array the size of the data that needs to be deseralized.
byte[] data = new byte[bytesRead];
// Copy the byte array into the toDeserialize buffer
Buffer.BlockCopy(
client.Buffer,
0,
data,
0,
bytesRead);
// Read the first Int32 tp get the packet length and then use the byte[4] to get the packetLength
byte[] packetLengthBytes = new byte[4];
Buffer.BlockCopy(
data,
0,
packetLengthBytes,
0,
packetLengthBytes.Length);
int packetLength = BitConverter.ToInt32(packetLengthBytes, 0);
// Now what do you recommend?
// If not all data is received, call
// networkStream.BeginRead(client.Buffer, 0, client.Buffer.Length, ReadCallback, client);
// and preserve the initial data in the client object
お時間とアドバイスをいただきありがとうございます。このテーマについてさらに学ぶことを楽しみにしています。