0

Heres the scenerio...

Server

  • I have TcpListener server that is accepting connections
  • When a connection is made, I wrap the TcpClient.GetStream() in a buffered stream.
  • Then I am using a BinaryFormatter to deserialize incoming data from the stream

Client

  • I connect to the server
  • When connected, I wrap the TcpClient.GetStream() in a buffered stream.
  • Then I use a BinaryFormatter to serialize data over the Stream.

All works wells for as long as the connection stays active. I've tested over periods of hours.

The Problem

  • Then I stop the Server to simulate a network fault (I'm using localhost)
  • The client will detect the fault (exception thrown/handled)
  • The client will re-connect later with a new TcpClient and new BufferedStream
  • The the client will use a new BinaryFormatter to start serializing data again.

Now however, the server will get all kinds of strange deserialization Exceptions. I've gone as low as looking at the bytes of the Stream and to my surprise found that the stream is being corrupted!... but only after a re-connect scenerio. And, getting rid of the BufferedStream and using the NetworkStream directly fixes the issue. You can re-connect many many times without seeing this issue.

What is going on with the BufferedStream? Every reconnect I create a new BufferedStream, but could the previous stream be affecting the new one some how?

Has anyone seen anything like this?

Unfortunatly I can't post the entire code, but here is an example of what I am doing...

Example Server Code

while (true)
{//Accept connections and spawn threads to handle incoming connections
     TcpClient connection = server.AcceptTcpClient();
}

//Done on another thread
Stream stream = new BufferedStream(connection.GetStream());
BinaryFormatter formatter = new BinaryFormatter();
object data = formatter.Deserialize(stream);

Example Client Code

_connection = new TcpClient();
_connection.Connect(_remoteAddress);
NetworkStream netStream = _connection.GetStream();
Stream stream = new BufferedStream(netStream);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, data);
stream.Flush();

Without using BufferedStream everything works ok. Also when reconnecting the above client proccess is repeated.

Derek
  • 39
  • 7
  • Post the relevant code. How could we possibly find the bug without seeing what you are doing? – usr May 23 '14 at 21:30
  • That by itself looks fine. Are you aware that you must flush the buffered stream after having written a message to make sure it is sent? (Remove the buffering entirely. It makes your program slower, now faster, and it might lead to bugs.) – usr May 23 '14 at 21:55
  • Yes, the stream is flushed after calling Serialize. I have found the oposite during testing, using a BufferedStream increases the performance by a factor of about 10, which is why I want to keep it. – Derek May 23 '14 at 22:04
  • Then you probably have disabled nagling. The TCP stack does its own, specialized buffering. Anyway, remove the buffering and retest just to help with debugging. Is the problem still there? – usr May 23 '14 at 22:16
  • Are you creating a new `BinaryFormatter` on the client at reconnect? – Jeffrey Hantin May 23 '14 at 22:19
  • Yes removing the BufferedStream fixes the re-connect problem, but makes the transfer much slower. Also, I am creating a new instance of BinaryFormatter on reconnect. Basicaly everything is new on reconnect... which is why this is soo puzzling. – Derek May 23 '14 at 22:25
  • I've addressed the re-connect issue without sacrificing much speed by writting to a MemoryStream first then calling MemoryStream.WriteTo(Stream) to write the data to the non-buffered NetworkStream. This solution works, but still doesn't explain the BufferedStream issue, and is less ideal for sending large objects as the entire object has to be serialized before anything is sent. – Derek May 23 '14 at 23:11
  • @Derek with the code shown we cannot find the bug. Probably, you are *not* instantiating everything freshly although it was your intention. What does it tell you that removing the buffering hides the problem? – usr May 24 '14 at 09:50

1 Answers1

0

I've addressed the re-connect issue without sacrificing much speed by writting to a MemoryStream first then calling MemoryStream.WriteTo(Stream) to write the data to the non-buffered NetworkStream. This solution works, but still doesn't explain the BufferedStream issue, and is less ideal for sending large objects as the entire object has to be serialized before anything is sent.

Still not sure what the BufferedStream issue is. And, to make it more confusing, I found out the code works flawlessly on one machine, but not on the other. Possible it's a driver issue?

But, Serializing to a MemoryStream first then calling MemoryStream.WriteTo(Stream) works well enough for me, and runs fine on all tested machines, so I went with that.

Derek
  • 39
  • 7