0

Long story short I am trying to send a string via TcpClient using StreamWriter.

Without changing any other code except swapping out these samples. They produce different results.

In code sample 1 the StreamReader picks up that it has DataAvailable and the message is received.

In code sample 2 it does not have DataAvailable so no message is received. I need to keep my underlying stream open hence needing to use the constructor of StreamWrite in sample 2.

Sample 1 - Write Method

    public void SendMessage(string message)
    {
        message = "TestMessage";

        //WORKING - Sample 1
        using (var sw = new StreamWriter(stream))
        {
            sw.Write(message);
            sw.Flush();
        }
    }

Sample 2 - Write Method

    public void SendMessage(string message)
    {
        message = "TestMessage";

        //NOT WORKING - Sample 2
        var encoding = new UTF8Encoding(false, true);
        using (var sw = new StreamWriter(stream, encoding, 1024, true))
        {
            sw.Write(message);
            sw.Flush();
        }
    }

Read Method

    public string ReadMessage()
    {
        if (!stream.DataAvailable)
            return null;

        //I have also tried
        //if(sr.Peek() == 0)
        //  return null;

        string message = sr.ReadToEnd();
        return message;
    }

NOTE: If I put both samples together with the working one last I get the message received "TestMessageTestMessage" so it is definitely writing to stream however it is not setting DataAvailable to true?

Any Idea's why?

Emcrank
  • 3
  • 2
  • 1
    Please provide a complete example of it both in the working and non working state. It is hard to tell what you are doing between the SendMessage and ReadMessage. – Scott Chamberlain Oct 12 '17 at 20:08
  • It is not directly related to the question, but the answers of https://stackoverflow.com/questions/27961274/reading-information-from-a-port-waits-even-though-data-available might give you another approach than relying on the DataAvailable property. – Ralf Bönning Oct 12 '17 at 20:08
  • Are you calling read method right after calling the write method? In this case DataAvailable property may have not been set by the time you checked it. Try putting a Thread.Sleep(100) right between your write and read and see if it works. – M. Usman Oct 12 '17 at 20:45
  • The read method is on its own thread in a while(true) loop with a Thread.Sleep(3000) at the end so it is constantly trying to read data from the stream so the ReadMessage method should fire the problem is the DataAvailable property is not true when using Sample 2. I will take a look at the other approach to the DataAvailable property in the meantime. Thanks. – Emcrank Oct 12 '17 at 21:06
  • 1
    StreamReader is very dangerous when used with a socket. It has its own buffer, it tries to fill it from the socket before you can Read() anything. That will work when a socket constantly sends data, but that is not typically how sockets are used. Especially not when you use "message" in the code. – Hans Passant Oct 12 '17 at 22:22

1 Answers1

1

The problem is your ReadToEnd() command which blocks indefinitely on a NetworkStream which has no end until closed. I tested your code and I went past the DataAvailable query and blocked on the ReadToEnd() command.

Your method that uses a constructor that allows the BaseStream to stay open means that you never have an end to your stream. When the working method closes the stream the ReadMessage method returns with everything in the stream.

The solution: Do not attempt to read to the end. Read in blocks while the data is available or introduce a terminating character and read to that character.

From MSDN:

ReadToEnd assumes that the stream knows when it has reached an end. For interactive protocols in which the server sends data only when you ask for it and does not close the connection, ReadToEnd might block indefinitely because it does not reach an end, and should be avoided.