0
votes

I am reading documentation on using TcpClient and NetworkStream to write and read from a Tcp connection stream. But I notice that all Microsoft's documentation is not using "using" block even thought both TcpClient and NetworkStream implement IDisposable.

So, I was wondering why is this.

I also notice in few examples that they write to stream and then immediately after, read from the stream. This does not feel right but I am new to networking but I wrote something like the code below to do exactly that.

While the code works, I am not sure how good and reliable it is though. Specifically, if data is not available to be read, once I check for it, the execution will move on. At that point, data may be available for reading but then it is to late, I already passed that point.

My questions are capitalized as code comments below

using (TcpClient client = new TcpClient())  // WHY NOT USING?
{
    client.Connect(ip, port);

    using (NetworkStream stream = client.GetStream())  // WHY NOT USING?
    {
        byte[] messageBytes = ...;
        if (stream.CanWrite)
        {
            await stream.WriteAsync(messageBytes, 0, messageBytes.Length);
            stream.Flush();
        }

        // IS THIS DATA GOING TO BE AVAILABLE AT THIS POINT?  
        // IF NOT, THEN YOU WILL HAVE NO OPPORTUNITY TO READ DATA 
        // SINCE NOTHING IS GOING TO TELL YOU WHEN IT IS GOING TO BE AVAILABLE.  
        // BY THE TIME IT IS AVAILABLE, THE EXECUTION MAY PASS THIS POINT, WHAT THEN???
        if (stream.CanRead)  
        {
            byte[] buffer = newe byte[1024];
            int readSoFar = 0;
            StringBuilder builder = new StringBuilder();

            while(stream.DataAwailable)
            {
                readSoFar = await stream.ReadAsync(buffer, 0, buffer.Length);
                builder.AppendFormat("{0}", Encoding.ASCII.GetString(buffer, 0, readSoFar));
            }

            string msg = builder.ToString();
        }
    }
}
1
they write to stream and then immediately after, read from the stream There are two streams per socket. The read and write streams are completely different streams. - Stephen Cleary

1 Answers

2
votes

TcpClient/NetworkStream/Socket have only one unmanaged resource under the hood. It is socket itself. Your code can have only 1 using block, and you will be ok. In your example, when code leaves using (NetworkStream) block, it closes underlying socket, and TcpClient.Dispose actually does nothing.

About Read/ReadAsync. The data is not available immediately. But these methods wait for one of 2 events: data appears on the socket, or other party closes tcp socket. As soon as 1 byte appears on the socket, these functions immediately return result. If another party closes connection, these functions return 0, which actually indicates end of stream.

Usually you shouldn't use DataAvailable property. In your example it can lead to unexpected behavior. You can just use Read/ReadAsync until they return zero.