Dragoon Aethis
Dragoon Aethis

Reputation: 169

Will C# NetworkStream.Read() wait until the specified amount of data is read?

In C/C++ read() on regular non-blocking network sockets will return immediately with the amount of data currently available in the buffer, up to the amount specified (so if we ask for 16 bytes and there are only 8 available at the moment, those 8 we'll get and it's up to us to call read() again and fetch all data).

In C# there's NetworkStream, which has built-in timeouts - does this mean that NetworkStream.Read() waits until either the timeout is reached or the amount of data requested is read, or will it give us any amount of data currently available in the buffer larger than 0 up to the amount requested (as the standard sockets do) even if there's time left?

Upvotes: 2

Views: 6183

Answers (3)

Stav Bodik
Stav Bodik

Reputation: 2134

The safe method is to use MemoryStream wich will make sure to wait and read all the stream to the memory , then u can use it as you like

     public void SaveUserTemplate(Stream stream)
     {
        MemoryStream memoryStream = new MemoryStream();
        stream.CopyTo(memoryStream);
        memoryStream.Position = 0;

      
        byte[] templatePathLength = new byte[4];
        memoryStream.Read(templatePathLength, 0, templatePathLength.Length);
        int nBytesTemplatePathLength = BitConverter.ToInt32(templatePathLength,0);

        ....

CopyTo function finally calls to this function:

github.com/microsoft/referencesource

private void InternalCopyTo(Stream destination, int bufferSize)
    {
        Contract.Requires(destination != null);
        Contract.Requires(CanRead);
        Contract.Requires(destination.CanWrite);
        Contract.Requires(bufferSize > 0);
        
        byte[] buffer = new byte[bufferSize];
        int read;
        while ((read = Read(buffer, 0, buffer.Length)) != 0)
            destination.Write(buffer, 0, read);
    }

Upvotes: 0

Bart Vanseer
Bart Vanseer

Reputation: 548

I solved it like this:

        byte[] TotalData = new byte[0];
        byte[] TempData = new byte[0];
        using (TcpClient TCPClient = new TcpClient())
        {
            try
            {
                TCPClient.Connect(somehost, someport);
            }
            catch (Exception eee)
            {
                // Report the connection failed in some way if necessary
            }
            if (TCPClient.Connected)
            {
                using (NetworkStream clientStream = TCPClient.GetStream())
                {
                    // You can reduce the size of the array if you know 
                    // the data received is going to be small, 
                    // don't forget to change it a little down too

                    byte[] TCPBuffer = new byte[524288];
                    int bytesRead = 0;

                    int loop = 0;
                    // Wait for data to begin coming in for up to 20 secs
                    while (!clientStream.DataAvailable && loop< 2000)
                    {
                        loop++;
                        Thread.Sleep(10);
                    }
                    // Keep reading until nothing comes for over 1 sec
                    while (clientStream.DataAvailable)
                    {
                        bytesRead = 0;

                        try
                        {
                            bytesRead = clientStream.Read(TCPBuffer, 0, 524288);
                            Array.Resize(ref TempData, bytesRead);
                            Array.Copy(TCPBuffer, TempData, bytesRead);
                            // Add data to TotalData
                            TotalData = JoinArrays(TotalData, TempData);
                        }
                        catch
                        {
                            break;
                        }

                        if (bytesRead == 0)
                            break;

                        Thread.Sleep(1000);
                    }
                }
            }
        }

The JoinArrays() method:

byte[] JoinArrays(byte[] arrayA, byte[] arrayB)
{
    byte[] outputBytes = new byte[arrayA.Length + arrayB.Length];
    Buffer.BlockCopy(arrayA, 0, outputBytes, 0, arrayA.Length);
    Buffer.BlockCopy(arrayB, 0, outputBytes, arrayA.Length, arrayB.Length);
    return outputBytes;
}

Upvotes: 1

khargoosh
khargoosh

Reputation: 1520

It will read available data up to the number of bytes specified in the parameters, as described on MSDN, unless the stream is closed via timeout or other exception.

The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.

Upvotes: 1

Related Questions