我正在编写一个使用TcpListener
作为服务器的程序。多个客户端连接到它并发送/接收数据包。
这些Packets
只是包含数据的序列化自定义类。我使用BinaryFormatter
来序列化和反序列化数据包:
[Serializable]
public class Packet
{
public static implicit operator byte[](Packet p)
{
using (var memoryStream = new MemoryStream())
{
new BinaryFormatter().Serialize(memoryStream, p);
return memoryStream.ToArray();
}
}
protected byte[] Serialize(object o)
{
using (var memoryStream = new MemoryStream())
{
new BinaryFormatter().Serialize(memoryStream, o);
return memoryStream.ToArray();
}
}
public static object Deserialize(byte[] data)
{
using (var memoryStream = new MemoryStream(data))
return new BinaryFormatter().Deserialize(memoryStream);
}
}
以下是我发送的数据包示例:
[Serializable]
public class Message : Packet
{
public string Text { get; set; }
public Message(string text)
{
Text = text;
}
public byte[] Serialize()
{
return Serialize(this);
}
}
现在我发送此数据的方式是首先创建一个Header
,它指定我们要序列化的数据包的长度,然后将该标头发送到NetworkStream
,然后,它发送实际的数据包。
我为这样的任务写了一个扩展类:
public static class StreamExtension
{
public static async Task WritePacket(this NetworkStream stream, byte[] packet)
{
var header = BitConverter.GetBytes(packet.Length); //Get packet length.
await stream.WriteAsync(header, 0, header.Length); //Write packet length as header.
await stream.WriteAsync(packet, 0, packet.Length); //Write actual packet.
Console.WriteLine($"Writing packet with length {packet.Length}");
}
}
现在,当我尝试连接时,它可以与第一个连接的客户端一起工作,它会发送和接收所有必要的数据包。但是当第二个客户端加入时,它最终会尝试反序列化甚至不发送的数据包。
我创建了一个try catch来查看问题是什么,我得到一个例外说:
二进制流'0'不包含有效的二进制头
这是在客户端接收数据的方法:
private async void ReceiveData()
{
var header = new byte[4]; //Indicator for how big our actual packet is.
var stream = Server.GetStream();
while (await stream.ReadAsync(header, 0, header.Length) != 0)
{
var packetLength = BitConverter.ToInt32(header, 0);
var buffer = new byte[packetLength];
await stream.ReadAsync(buffer, 0, buffer.Length); //Read packet.
try {
var receivedPacket = Packet.Deserialize(buffer);
lbLog.Items.Add($"Received packet: {receivedPacket.GetType()}");
if (receivedPacket is SetPiece)
{
var setPiece = receivedPacket as SetPiece;
MyPiece = setPiece.Piece;
lblPiece.Text = $"You are {MyPiece}";
}
else if (receivedPacket is StartNew)
{
foreach (var box in Controls.OfType<PictureBox>())
box.Image = null;
}
else if (receivedPacket is SetTurn)
{
var setTurn = receivedPacket as SetTurn;
IsTurn = setTurn.IsMine;
lblTurn.Text = setTurn.IsMine ? "Your Turn" : $"{setTurn.Name}'s Turn";
}
else if (receivedPacket is Log)
{
var log = receivedPacket as Log;
lbLog.Items.Add(log.Message);
}
}
catch
{
File.AppendAllLines("errors.txt", new[] { $"Error occurred with packet. Length of {buffer.Length}" });
}
}
}
以下是服务器控制台的日志:
这是错误日志:
Error occurred with packet. Length of 162
Error occurred with packet. Length of 256
Error occurred with packet. Length of 1952797486
如果长度为1952797486的数据包从未发送过,我们怎么会出错呢?
关于我做错的任何想法?