9

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
  • 4,641
  • 11
  • 46
  • 78

4 Answers4

30

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.

dtb
  • 198,715
  • 31
  • 379
  • 417
  • 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 Aug 05 '11 at 14:59
  • It returns 0 when "there will be no further data for reading". For example, if there is a disconnection. The method blocks otherwise. – Mark H Aug 05 '11 at 15:01
  • 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... – Fabrice Mar 02 '12 at 15:15
  • 2
    That's not *misleading*, that's just plain *wrong*. – J... Jul 11 '17 at 12:56
  • The paragraph has been changed to sound _less_ irritating on the new docs platform (https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.networkstream.read#Remarks): "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." – Ray Feb 04 '18 at 12:13
  • In my case. I added ReadTimeout to avoid waiting forever for the Read function. – aerobrain Feb 20 '21 at 08:01
7

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.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
5

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.

Ryszard Dżegan
  • 21,718
  • 6
  • 31
  • 53
0

If no data is available for reading, the Read method will block until data is available. Consider using the Async Socket functions if you don't want to block. http://msdn.microsoft.com/en-us/library/bbx2eya8.aspx

Dave
  • 266
  • 1
  • 9