NetworkStream.Read 挂起/阻塞的原因有哪些?

发布于 2024-11-28 00:47:16 字数 1335 浏览 0 评论 0原文

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

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)

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

晨曦慕雪 2024-12-05 00:47:16

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

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

应该说:

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

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.

笑饮青盏花 2024-12-05 00:47:16

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

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

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.

迎风吟唱 2024-12-05 00:47:16

处理 NetworkStream 时的一个常见错误是通过 Write 方法发送未完成的命令,这会导致连续的 Read 调用挂起。

请参阅以下尝试将用户名发送到打开的 FTP 端口的示例。它期望像 331 Please指定密码 这样的响应,但 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 短语放在命令末尾,一切都会开始按预期工作。

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.

淡写薰衣草的香 2024-12-05 00:47:16

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文