Search code examples
c#.netsocketsnetworkstreamread-write

NetworkStream write not newlining if not thread slept


I have two pieces of software, one being a server and the other being the client interface.

In my server I am taking and handling request then returning a string through a method I wrote "reply"

    public static void reply(string buffer, NetworkStream stream)
    {
        stream.Write(Encoding.ASCII.GetBytes(buffer), 0, buffer.Length);
    }

the issue I am having is that for example if I were to do the below code

for(int i = 0; i<5; i++){
reply("SOME REPLY", stream);
}

the above code will write random newlined lines back to the client like this:

SOME REPLY
SOME REPLYSOME REPLY
SOME REPLY
SOME REPLYSOME REPLYSOME REPLY
SOME REPLYSOME REPLY
SOME REPLY
SOME REPLY

If I were to have put a 200ms Thread.Sleep call in the forloop it would have correctly newlined the responses. On the client side the below code is how we're reading from the server and printing to console:

        Byte[] bytes = new Byte[256];
        NetworkStream stream = endpoint.GetStream();
        int i;
        while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
        {
            Console.WriteLine(System.Text.Encoding.ASCII.GetString(bytes, 0, i));
        }

Solution

  • Your problem is that the client is not sending a newline, so the server basically has no clue where to put the newlines. The fact that you're getting 'some' newlines, has to do with the way the stream is used, a NetworkStream will always read any data available when you call read, or wait until -some- data is available; there's no guarantee that what you receive is what you want. You may read all the data from a stream on the server side in your application, then add a newline (Because of the Console.WriteLine call), and then continue on to read the next part of the message.

    I suppose the easiest way to work around this is to simply change the reply("SOME REPLY", stream); call to reply("SOME REPLY" + Environment.NewLine, stream); and then change the Console.WriteLine call on the server-side to a simple Console.Write call.

    A better, but slightly more complex way of handling fragmented or buffered messages would be to always send a 'byte-count' in front of your message from the client side, so that the server knows how many bytes to read before adding a newline:

    Pseudocode:

    Client => Send([number of bytes] + [data])
    Server => Read([number of bytes] (Field))
    Server => Read([data]) until received bytes count == [number of bytes]