反序列化通过TCP发送的数据

时间:2009-09-30 08:51:43

标签: c# .net serialization tcp

我遇到通过TCPClient发送对象的问题。首先,我将它们序列化为字节数组然后发送它们。 TCPListener收到一些数据,但反序列化器抛出异常“意外的流结束”。

以下是收件人代码:

    public void start()
    {
        TcpListener listener = new TcpListener(IPAddress.Any, 8090);
        listener.Start();

        while (true)
        {
            TcpClient client = listener.AcceptTcpClient();
            processClient(client);
        }
    }

    public void processClient(TcpClient client)
    {
        NetworkStream net = client.GetStream();


        ReadData(net);

        byte[] response  = Encoding.UTF8.GetBytes("Hello from the server.");
        net.Write(response, 0, response.Length);
        net.Close();
        client.Close();
    }

void ReadData(NetworkStream netstream)
{
    byte[] buffer = new byte[2048];
    System.IO.MemoryStream memStream = new System.IO.MemoryStream();

    netstream.ReadTimeout = 5000;

    int bytes = -1;

    while ((bytes = netstream.ReadByte()) != -1)
    {
        memStream.WriteByte((byte)bytes);
    }

    System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bform = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();


    Packet packet = (Packet)bform.Deserialize(memStream);

    OnMessageArrived(this, new MessageEventArgs(packet.From.ToString(), packet.Data.ToString()));

    memStream.Close();
    netstream.Close();

}

这是发件人代码:

    public void sendData(string to, Packet data)
    {
        TcpClient client = new TcpClient();

        MemoryStream mstream = new MemoryStream();

        client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8090));
        if (client.Connected)
        {
            NetworkStream stream = client.GetStream();

            System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bform = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            bform.Serialize(mstream, data);

            byte[] buffer = new byte[2048];
            mstream.Read(buffer, 0, buffer.Length);

            stream.Write(buffer, 0, buffer.Length);
            stream.Flush();
            stream.Close();
            client.Close();
        }
    }

发件人主要方法:

    static void Main(string[] args)
    {
        SimplestTCPIP.Client client = new SimplestTCPIP.Client();

        Packet packet = new Packet("client", "server", IPAddress.Parse("127.0.0.1"));

        client.sendData("server", packet);

        Console.WriteLine("IP: " + GetIP().ToString());
        Console.Read();
    }

接收者主要方法:

    static void Main(string[] args)
    {
        SimplestTCPIP.Server server = new SimplestTCPIP.Server();

        server.OnMessageArrived += new SimplestTCPIP.Server.MessageArrived(server_OnMessageArrived);

        Thread thread = new Thread(server.start);
        thread.Start();

    }

    static void server_OnMessageArrived(object sender, SimplestTCPIP.Server.MessageEventArgs m)
    {
        Console.WriteLine(m.From + " : " + m.Text);
    }

1 个答案:

答案 0 :(得分:3)

在sendData方法中,将对象序列化为内存流,然后将其读回2048字节的缓冲区,然后再将其写入网络流。如果序列化对象是> 2048字节你会遇到问题。我会尝试直接序列化到网络流,或者至少使用与ReadData方法中相同类型的代码,逐字节写入。

编辑:

数据的大小可能不是问题。您仍应避免使用硬编码缓冲区大小,并坚持使用您在注释中提及的代码更改。鉴于你的评论,问题出在其他地方。 在发送方和接收方中,您都要写入内存流,然后从中读取。除非在写入和读取之间将流中的当前位置设置为零,否则不能这样做。

所以在客户端的sendData方法中添加行

mstream.Seek(0, SeekOrigin.Begin);

之后

bform.Serialize(mstream, data);

在服务器的ReadData方法中添加行

memStream.Seek(0, SeekOrigin.Begin);

之前

Packet packet = (Packet)bform.Deserialize(memStream);

这样,在您尝试读取内存流之前,内存流就会设置为开头。

我认为您可以一起跳过内存流,只读取和写入网络流,但您可能还有其他原因。