使用Socket的随机序列化异常

时间:2013-11-05 04:06:14

标签: c# sockets serialization

我正在尝试使用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);
    }
}

有人看错了什么吗?

1 个答案:

答案 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