我在 C# 中有一个异步 TCP 套接字服务器,它是使用 Socket 的 TcpListener/TcpClient 包装器制作的。一般来说,我对网络很陌生,所以我不知道 TCP 如何处理发送的数据,以及它如何不保留消息边界。经过一番研究,我想我已经想出了一个可靠的解决方案,但我想知道是否有人对我有更多建议。
目前,我发送的数据是使用 protobuf(Google 的数据交换库)https://code.google.com/p/protobuf/的序列化类对象的字节 []
在我序列化我的数据之后,在它被发送之前,我决定在字节数组的开头附加一个 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;
}
我有点卡在服务器端。我让它读取 packetLength 变量,方法是使用 Buffer.BlockCopy 复制前 4 个字节,然后使用 BitConverter.ToInt32 读取我应该得到的长度。我不确定我是否应该不断地将传入数据读入特定于客户端的 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
感谢您的时间和建议,我期待更多地了解这个主题。