不,由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可以从发送方填充更多数据。
然后还有你(.NET API调用者),也在做同样的事情,调用Read()方法并将数据复制到你的缓冲区中。
因此,如果你想一想,一个256Kb的消息通过电线传输,64K坐在
tcpip.sys缓冲区里,64K坐在
afd.sys缓冲区里,而且你在请求一个4K(你的bufferSize变量)的chunk之后设置了一个断点,我们会看到128K的ACK被接收者返回给发送者,并且由于
tcpip.sys缓冲区已经满了(假设大小为64K),现在你受到调试会话的阻塞,
tcpip.sys将不得不告诉发送者停止发送字节,因为它无法快速处理它们。
实际上(即没有设置断点的情况下!),我见过GC引起这样的行为。曾经看到一个3秒钟的垃圾回收让所有的操作系统缓冲区都填满了。