views:

314

answers:

1

Hi, I have problem with sending objects via TCPClient. At first, I serialize them into byte array and then I send them. TCPListener recieves some data, but deserializer is throwing exception "Unexpected end of stream".

Here is reciever code:

    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();

}

And here is sender code:

    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();
        }
    }

Sender main method: 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();
    }

Reciever main method:

    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  A: 

In your sendData method you serialize the object to a memory stream and then read it back into a buffer of 2048 bytes before writing it to the network stream. If the serialzed object is > 2048 bytes you would have a problem. I would try just serializing directly to the network stream or at least using the same kind of code as in your ReadData method where you write byte by byte.

Edit:

The size of the data is probably not the problem. You should still avoid the hard coded buffer size and stick with the code change you mention in the comment. Given your comment the problem lies elsewhere. In both your sender and your receiver you write to a memory stream and then read from it. You can't do that unless you set the current position in the stream back to zero between the write and read.

So in your sendData method on the client add the line

mstream.Seek(0, SeekOrigin.Begin);

right after

bform.Serialize(mstream, data);

And in the ReadData method of your server add the line

memStream.Seek(0, SeekOrigin.Begin);

right before

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

That way the memory stream is set to the beginning before you try and read from it.

I think you could just skip the memory stream all together and just read and write to the network stream, but you might have other reasons for it.

Mike Two
I tried this code: while ((bytes = mstream.ReadByte()) != -1) { stream.WriteByte((byte)bytes); stream.Flush(); }But it throws another exception :( Something like "Attempt to reconstruct empty stream".
Klinki