我正在尝试使用Socket在两台计算机之间来回发送数据。数据采用序列化Packet对象的形式。
在本地网络上的另一台计算机上测试程序时,我得到随机的SerializationExceptions,以便没有数据通过。
程序一致地发送不同的数据,所以当再次发送它时再次传递时,它有时会通过,有时会再次遇到相同的SerializationException。如果我捕获异常并使其保持运行,所有数据最终都会通过,但需要多次尝试。
异常说:“输入流不是有效的二进制格式。起始内容(以字节为单位)是[字节数据]”
不确定我的问题究竟在哪里。我发送的数据量最大(~100kb最大值)总是通过。较小的(50-70字节)有问题。这与我的序列化和读/写数据有关。
套接字定义如下:
SocketMain = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
发送&阅读方法。我知道这可能是一种可怕的方式,并可能最终成为我的问题。建议:
public void SendPacket(Packet P)
{
using (MemoryStream MS = new MemoryStream())
{
BinaryFormatter BF = new BinaryFormatter();
BF.Serialize(MS, P);
SocketMain.Send(MS.ToArray());
}
}
public void ReadPacket()
{
byte[] BufferArray = new byte[131072];
int BytesReceived = SocketMain.Receive(BufferArray);
byte[] ActualData = new byte[BytesReceived];
Buffer.BlockCopy(BufferArray, 0, ActualData, 0, BytesReceived);
using (MemoryStream MS = new MemoryStream(ActualData))
{
BinaryFormatter BF = new BinaryFormatter();
HandlePacket((Packet)BF.Deserialize(MS));
}
}
示例包对象。这是我较小的一个。我认为这可能是造成这个问题的那个,但我不知道我怎么说。
[Serializable()]
public class Packet4BlockVerify : Packet, ISerializable
{
public byte Index;
public string MD5Hash;
public Packet4BlockVerify(int Index, string MD5Hash): base(4)
{
this.Index = (byte)Index;
this.MD5Hash = MD5Hash;
}
protected Packet4BlockVerify(SerializationInfo info, StreamingContext context)
{
this.ID = info.GetByte("ID");
this.Index = info.GetByte("Index");
this.MD5Hash = info.GetString("MD5Hash");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("ID", this.ID);
info.AddValue("Index", this.Index);
info.AddValue("MD5Hash", this.MD5Hash);
}
}
有人看错了什么吗?
答案 0 :(得分:2)
您没有读取您发送的所有字节。您的来电:
int BytesReceived = SocketMain.Receive(BufferArray);
返回任意数量的字节。您需要将发送的字节与剩余字节的大小预先挂起,读取然后继续读取,直到您拥有所有字节,然后再尝试反序列化。
TCP发送一个连续的字节流,因此您的接收调用会读取任意大小的块。其中一个重载可以指定您希望接收的字节数,因此在读取了您期望的数字字节后,您可以使用它。 e.g。
// Warning untested! (but you get the idea)
// when sending
var payload = MS.ToArray();
var payloadSize = payload.Length;
mySocket.Send(BitConverter.GetBytes(payloadSize));
mySocket.Send(payload);
// when recieving
mySocket.Recieve(myBuffer, sizeof(int), SocketFlags.None);
var payloadSize = BitConverter.ToInt32(myBuffer, 0);
mySocket.Recieve(myBuffer, payloadSize, SocketFlags.None);
// now myBuffer from index 0 - payloadSize contains the payload you sent