3

所以我最近在做一些工作,当有人告诉我,如果在Stream.Read网络流上执行 a 是通过在 a 上调​​用 .NET 中的一个获得的GetResponseStreamWebResponse或者那些被缓冲的。

他说如果你在你正在阅读的代码中设置一个断点,你就不会停止网络流量。我觉得这很奇怪,但也希望这是真的。这是如何运作的?它甚至准确吗?

using (Stream webResponseStream = this.webResponse.GetResponseStream())
{
   byte[] readBuffer = new byte[bufferSize];
   int bytesRead = webResponseStream.Read(readBuffer, 0, bufferSize);
   while (bytesRead > 0)
   {
        bytesRead = webResponseStream.Read(readBuffer, 0, bufferSize);
        // If I put a breakpoint here, does network activity stop?
   }
}
4

3 回答 3

5

不, GetResponseStream返回的 Stream 对象没有缓冲。

您的第二部分(关于设置断点)的简短回答是您的同事不正确。网络流量将停止,但最终,并描述“最终”,请继续阅读以了解更多详细信息。

Bing用于“SO_RCVBUF”、“tcp 接收窗口大小”、“vista 自动缩放”,以获得更多一般信息。

详细部分

让我们从这个开始,这是 Windows 网络堆栈的文本视图:

++ .NET 网络 API

++ --- Winsock DLL(用户模式)

++ ------ afd.sys(内核模式)

++ --------- tcpip.sys

++ ------------ ndis

++ --------------- 网络接口(hal)

这是一个粗略的堆栈,掩盖了一些细节,但总体思路是 .NET 调用 Winsock 用户模式 ​​dll,然后将大部分实际工作推送到其表亲AFD(辅助功能驱动程序),然后推送到 tcpip 子系统等等..

AFD级别,有一个缓冲区,通常在8K 和 64K之间,但对于 Vista(及更高版本),它也可以扩展。此设置也可以通过注册表设置 ( HKLM\SYSTEM\CurrentControlSet\services\AFD\Parameters ) 控制。

此外,tcpip.sys 也有一个缓冲区,类似于 AFD 的缓冲区。我相信打开套接字时传递的 *SO_RCVBUF* 设置也可以改变这一点。

本质上,当您接收数据时,代表您的tcpip.sys会继续获取数据,并一直告诉发送者它已获取数据( ACK),并一直这样做直到其缓冲区已满。但与此同时,afd.sys通过向 tcpip.sys 请求数据(然后将其复制到自己的缓冲区中)来清除tcpip.sys缓冲区,因此tcpip.sys可以填充来自发送方的更多数据。

然后是你(.NET API 调用者),他也在做同样的事情,调用 Read() 方法并将数据复制到缓冲区中。

因此,如果您考虑一下,一条 256Kb 的消息通过网络传输,64K 位于tcpip.sys缓冲区中,64K 位于afd.sys缓冲区中,并且您在请求一个 4K(您的 bufferSize 变量)块后设置了一个断点,我们正在查看收到的 128K ACK'ed 返回给发送者,并且由于tcpip.sys缓冲区现在已满(假设为 64K 大小)(并且您被调试会话阻止),tcpip.sys将没有选项但是告诉发送者停止通过网络发送字节,因为它不能足够快地处理它们。

实际上(即有人没有设置断点!),我已经看到 GC 会引发这种行为。看到一个 3 秒垃圾收集的案例,它让所有操作系统缓冲区填满。

于 2012-01-20T07:46:46.687 回答
2

这是准确的。TCP 由 Windows TCP/IP 驱动程序堆栈实现。在程序中设置断点不会阻止驱动程序从服务器下载数据。直到驱动程序决定使用过多的内核池空间来缓冲数据。没有记录的确切规则。

这是一种优化,是操作系统中的标准优化。该策略使 TCP 传输非常高效,它不取决于您的程序的响应速度,仅取决于连接的带宽以及驱动程序堆栈对网卡中断的响应速度。它非常擅长,这是司机的工作。

于 2012-01-20T02:10:37.373 回答
0

默认情况下不缓冲NetworkStream。当您在读取此流的过程中放置​​断点时,正在向底层套接字发送数据的客户端将阻塞并等待远程套接字准备好再次接收。客户端将无法写入套接字,所以,是的,网络流量停止了。

这是一篇文,说明了如何使用BufferedStream类对其进行缓冲。

于 2012-01-19T22:57:23.887 回答