I'm trying to send data back and forth between two computers using a Socket (TCP). The data is in the form of serialized Packet objects.
At an early point in the application, it must send 25 or so Packets of the same type to the other side. See Case 1 in HandlePacket(). After a few Packets of this type are sent (2 to 5, it's random), the other side crashes with a SerializationException: "Binary stream '0' does not contain a valid BinaryHeader."
I've confirmed that I am always reading the same amount of data from the socket that was sent from the other computer, and I've also confirmed with an MD5 hash that, when the exception is thrown, the data received is not the same actual data that was sent.
Keep in mind that some packets of the type that is failing to deserialize actually do make it through and are processed correctly. I can't figure out why this is happening.
Also, Packets are typically responded to as soon as they are received, so the Send and Read methods usually run on the same thread. Here's my code to send and receive Packets, can anyone see anything wrong?
public void SendPacket(Packet P)
{
using (MemoryStream MS = new MemoryStream())
{
BinaryFormatter BF = new BinaryFormatter();
BF.Serialize(MS, P);
byte[] Payload = MS.ToArray();
int PayloadSize = Payload.Length;
SocketMain.Send(BitConverter.GetBytes(PayloadSize));
SocketMain.Send(Payload);
Console.WriteLine("Sent:" + P.GetType().ToString() + ", " + Payload.Length + " | " + Utility.GetMD5Hash(Payload));
}
}
public void ReadPacket()
{
byte[] BufferArray = new byte[131072];
SocketMain.Receive(BufferArray, sizeof(int), SocketFlags.None);
int PayloadSize = BitConverter.ToInt32(BufferArray, 0);
SocketMain.Receive(BufferArray, PayloadSize, SocketFlags.None);
byte[] Payload = BufferArray.Take(PayloadSize).ToArray();
Console.WriteLine("Received:" + PayloadSize.ToString() + " | " + Utility.GetMD5Hash(Payload));
using (MemoryStream MS = new MemoryStream(Payload))
{
BinaryFormatter BF = new BinaryFormatter();
HandlePacket((Packet)BF.Deserialize(MS));
}
}
private void HandlePacket(Packet P)
{
switch (P.ID)
{
case 1:
SendPacket(new Packet2InitializeData(SystemInformation.PrimaryMonitorSize.Width, SystemInformation.PrimaryMonitorSize.Height));
InitializeScreenBlockList();
int Index = 0;
foreach (ScreenBlock SB in ScreenBlocks)
{
SB.UpdateScreenBlock();
//------------------------------------------------------
SendPacket(new Packet3BlockUpdate(Index, SB)); //While sending these packets, the exception occurs.
//------------------------------------------------------
Index++;
}
WasInitializationDataSent = true;
break;
case 2:
HandlePacket2InitializeData((Packet2InitializeData)P); break;
case 3:
HandlePacket3BlockUpdate((Packet3BlockUpdate)P); break;
case 4:
HandlePacket4BlockVerify((Packet4BlockVerify)P); break;
case 5:
HandlePacket5BlockRequest((Packet5BlockRequest)P); break;
}
}
Here's the packet object:
[Serializable()]
public abstract class Packet : ISerializable
{
public byte ID;
public Packet()
{
}
public Packet(byte ID)
{
this.ID = ID;
}
public abstract void GetObjectData(SerializationInfo info, StreamingContext ctxt);
}
And the packet that always causes the exception. A few packets of this type do make it through.
[Serializable()]
public class Packet3BlockUpdate : Packet, ISerializable
{
public ushort Index;
public Image BlockImage;
public string MD5;
public Packet3BlockUpdate(int Index, ScreenBlock Block): base(3)
{
this.Index = (ushort)Index;
this.BlockImage = Block.Image;
MemoryStream MS = new MemoryStream();
this.BlockImage.Save(MS, ImageFormat.Jpeg);
MD5 = Utility.GetMD5Hash(MS.ToArray());
}
protected Packet3BlockUpdate(SerializationInfo info, StreamingContext context)
{
Image A = new Bitmap(1, 1);
this.ID = info.GetByte("ID");
this.Index = info.GetUInt16("Index");
this.BlockImage = (Image)info.GetValue("Image", A.GetType());
this.MD5 = info.GetString("MD5");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("ID", this.ID);
info.AddValue("Index", this.Index);
info.AddValue("Image", this.BlockImage);
info.AddValue("MD5", this.MD5);
}
}