当我告诉它时,为什么这段代码缓冲TCP输出?

时间:2012-01-06 23:46:17

标签: c# http tcp

这是我用来测试嵌入式产品上的Web服务器的代码,当HTTP请求分散在多个TCP数据包中时,该服务器表现不佳:

/* This is all within a loop that cycles size_chunk up to the size of the whole 
 * test request, in order to test all possible fragment sizes. */
TcpClient client_sensor = new TcpClient(NAME_MODULE, 80);    
client_sensor.Client.NoDelay = true;    /* SHOULD force the TCP socket to send the packets in exactly the chunks we tell it to, rather than buffering the output. */
/* I have also tried just "client_sensor.NoDelay = true, with no luck. */
client_sensor.Client.SendBufferSize = size_chunk; /* Added in a desperate attempt to fix the problem before posting my shameful ignorance on stackoverflow. */
for (int j = 0; j < TEST_HEADERS.Length; j += size_chunk)
{
    String request_fragment = TEST_HEADERS.Substring(j, (TEST_HEADERS.Length < j + size_chunk) ? (TEST_HEADERS.Length - j) : size_chunk);
    client_sensor.Client.Send(Encoding.ASCII.GetBytes(request_fragment));     
    client_sensor.GetStream().Flush();   
}
/* Test stuff goes here, check that the embedded web server responded correctly, etc.. */

看看Wireshark,我看到只有一个TCP数据包输出,它包含整个测试头,而不是我期望的大约header length / chunk size个数据包。我以前使用NoDelay来关闭Nagle算法,它通常就像我期望的那样工作。 NoDelay {{1}}的在线文档明确指出“在调用NetworkStream.Write后立即发送数据”,因此我认为我一直都在正确使用它。

无论我是否单步执行代码,都会发生这种情况。 .NET运行时是否优化了我的数据包碎片?

我正在运行x64 Windows 7,.NET Framework 3.5,Visual Studio 2010。

4 个答案:

答案 0 :(得分:2)

TcpClient.NoDelay并不意味着字节块不会聚合到单个数据包中。这意味着不会延迟字节块以便聚合成单个数据包。

如果要强制数据包边界,请使用Stream.Flush

答案 1 :(得分:2)

格儿。这是我的防病毒软件阻碍了。最近的更新导致它开始干扰通过缓冲所有输出向端口80发送HTTP请求,直到看到最后的“\ r \ n \ r \ n”标记,无论操作系统如何尝试处理出站TCP交通。我应该先检查一下,但是我多年来一直在使用同样的防病毒程序,之前从未遇到过这个问题,所以我甚至都没有想到它。一切都按照我禁用防病毒时的方式工作。

答案 2 :(得分:1)

MSDN docs显示设置TcpClient.NoDelay = true,而不是TcpClient.Client.NoDelay属性。你试过吗?

答案 3 :(得分:0)

您的测试代码很好(我假设您发送了有效的HTTP)。您应该检查的是TCP服务器从TCP连接读取时表现不佳的原因。 TCP是一种流协议 - 这意味着除非在数据协议中明确指定这些大小,否则不能对数据包的大小做任何假设。例如,您可以使用固定大小(2字节)前缀为您的所有数据包添加前缀,该前缀将包含要接收的数据的大小。

读取HTTP时,通常会读取几个阶段:读取HTTP行,读取HTTP标头,读取HTTP内容(如果适用)。前两个部分没有任何尺寸规格,但它们有特殊的分隔符(CRLF)。

Here是一些有关如何读取和解析HTTP的信息。