10

MSDN 文档似乎暗示 NetworkStream.Read 总是会立即返回。如果未找到数据,则返回 0。但是,我有一些当前部署的代码,仅在某些情况下(我还没有弄清楚哪些情况),NetworkStream.Read 似乎挂起。这是我能够从转储文件中收集的堆栈跟踪

00000000705ae850 000007fef784f60d DomainBoundILStubClass.IL_STUB(IntPtr,字节*,Int32,System.Net.Sockets.SocketFlags)
00000000705ae930 000007fef785c930 System.Net.Sockets.Socket.Receive(字节 [],Int32,Int32,System.Net.Sockets.SocketFlags,System.Net.Sockets.SocketError ByRef)
00000000705ae9b0 000007ff004eb668 System.Net.Sockets.NetworkStream.Read(字节 [],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,布尔值)

我注意到 NetworkStrea.Read 实际上调用了 Socket.Receive,据我所知,这可能是阻塞的。我只是不知道为什么有时它会阻塞,有时它不会。

4

4 回答 4

30

NetworkStream.Read文档的备注部分具有误导性。它说:

该方法将数据读入缓冲区参数,并返回成功读取的字节数。如果没有数据可供读取,Read 方法返回 0。Read操作读取可用数据,最多为 size 参数指定的字节数。如果远程主机关闭连接,并且已接收到所有可用数据,则 Read 方法将立即完成并返回零字节。

它应该说:

该方法将数据读入缓冲区参数,并返回成功读取的字节数。如果没有数据可供读取,Read 方法将阻塞,直到数据可用或连接关闭。Read 操作读取尽可能多的数据,最多为 size 参数指定的字节数。如果远程主机关闭连接,并且已接收到所有可用数据,则 Read 方法将立即完成并返回零字节。

于 2011-08-05T14:54:29.563 回答
7

有时套接字缓冲区中已经有数据,有时可能没有。

看到一个块的一个常见原因NetworkStream是,如果连接的每一端都期望另一端关闭。例如,如果您建立一个 HTTP 1.1 保持活动连接,但仍然执行“读取直到连接关闭”的方式来获取内容。

于 2011-08-05T14:54:31.980 回答
5

处理时的一个常见错误是通过导致连续呼叫挂起的方法NetworkStream发送未完成的命令。WriteRead

请参阅下面的示例,该示例尝试将用户名发送到打开的 FTP 端口。它期望响应像331 请指定密码,但Read方法挂起:

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

一个神奇的解决方案是将第一行替换为以下内容:

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

只需在命令末尾添加\r\n短语,一切都会按预期开始工作。

于 2015-10-13T10:38:48.403 回答
0

如果没有数据可供读取,Read 方法将阻塞直到数据可用。如果您不想阻塞,请考虑使用异步套接字函数。 http://msdn.microsoft.com/en-us/library/bbx2eya8.aspx

于 2011-08-05T15:00:53.233 回答