0

我正在尝试使用套接字仅在两台计算机之间来回发送数据。数据采用序列化的 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);
    }
}

有人看到有什么不对吗?

4

1 回答 1

2

您没有读取您发送的所有字节。您的接听电话:

int BytesReceived = SocketMain.Receive(BufferArray);

返回任意数量的字节。您需要在发送的字节前面加上剩余字节的大小,然后继续读取,直到您拥有所有字节,然后再尝试反序列化。

TCP 发送一个连续的字节流,因此您的接收调用读取任意大小的块。您可以指定要接收的字节数之一,因此在读取您期望的字节数后,您可以使用它。例如

// 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
于 2013-11-05T05:34:08.383 回答