What are some reasons NetworkStream.Read would hang/block?

12,018

Solution 1

The Remarks section of the documentation for NetworkStream.Read is misleading. It says:

This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. 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.

It should say:

This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method blocks until data becomes available or the connection is closed. 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.

Solution 2

Sometimes there'll be data already in the socket buffer and sometimes there won't, presuambly.

One common reason for seeing a NetworkStream block is if each side of the connection is expecting the other to close. For example, if you make an HTTP 1.1 keep-alive connection, but still do the "read until the connection is closed" way of getting content.

Solution 3

One common mistake while dealing with NetworkStream is sending unfinished commands via Write method which causes a consecutive Read call hanging.

See the below example that tries to send a user name to an opened FTP port. It expects a respond like 331 Please specify the password but the Read method hangs:

var request = Encoding.ASCII.GetBytes("user [username]");
networkStream.Write(request, 0, request.Length);
var streamReader = new StreamReader(networkStream);
var response = streamReader.ReadLine(); // <-- hangs

A magic solution is to replace the first line with the following:

var request = Encoding.ASCII.GetBytes("user [username] \r\n");

By simply adding \r\n phrase at the end of the command, everything will just start to work as expected.

Share:
12,018
Mark
Author by

Mark

Updated on June 04, 2022

Comments

  • Mark
    Mark almost 2 years

    MSDN documentation seems to suggest that NetworkStream.Read will always return immediately. If no data is found it returns 0. However, I have some code that is currently deployed, that only in some cases (and I haven't figured out which ones yet), NetworkStream.Read appears to hang. Here is the stack trace which i was able to gather from a dump file

    00000000705ae850 000007fef784f60d DomainBoundILStubClass.IL_STUB(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
    00000000705ae930 000007fef785c930 System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef)
    00000000705ae9b0 000007ff004eb668 System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32)
    00000000705aea40 000007fef784e6ae MySocketStuff.SocketConnectCallback(System.IAsyncResult)
    00000000705aeb20 000007fef84f2bbb System.Net.LazyAsyncResult.Complete(IntPtr)
    00000000705aeb90 000007fef7853c7b System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
    00000000705aebe0 000007fef784e5d3 System.Net.ContextAwareResult.Complete(IntPtr)
    00000000705aec40 000007fef7d027f9 System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr)
    00000000705aeca0 000007fef8b9815e System.Net.Sockets.Socket.ConnectCallback()
    00000000705aed20 000007fef93e14c2 System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(System.Object, Boolean)
    

    I notice that the NetworkStrea.Read actually calls Socket.Receive which can be blocking as far as I understand. I just don't know why sometimes it would block and sometimes it would not.

  • Mark
    Mark over 12 years
    But the documentation says the opposite... "This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0"
  • Mark H
    Mark H over 12 years
    It returns 0 when "there will be no further data for reading". For example, if there is a disconnection. The method blocks otherwise.
  • Ghost
    Ghost about 12 years
    I noticed that it blocks on .NET 4.0, in Azure's Compute Emulator, but not in Azure. How handy! You don't know what to expect...
  • Jacky
    Jacky over 7 years
    This saved my day
  • J...
    J... almost 7 years
    That's not misleading, that's just plain wrong.
  • Syroot
    Syroot about 6 years
    The paragraph has been changed to sound less irritating on the new docs platform (docs.microsoft.com/en-us/dotnet/api/…): "If the socket is closed, the Read method returns 0. 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."
  • S Meaden
    S Meaden over 5 years
    this is a good answer because it highlights how the problem lines could be in the lines above
  • colin lamarre
    colin lamarre over 4 years
    this might just be THE answer! so nice to find that!
  • aerobrain
    aerobrain about 3 years
    In my case. I added ReadTimeout to avoid waiting forever for the Read function.