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

发布于 2024-12-25 09:17:34 字数 1659 浏览 0 评论 0原文

这是我用来测试嵌入式产品上的网络服务器的代码,当 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 数据包发出,其中包含整个测试标头,而不是我期望的大约标头长度/块大小数据包。我之前曾使用NoDelay关闭Nagle算法,它通常会像我期望的那样工作。 NoDelay 的在线文档位于 http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.nodelay%28v=vs.90%29.aspx明确指出“发送数据在其相关代码示例中调用 NetworkStream.Write 后立即执行此操作,因此我认为我一直以来都正确使用了它。

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

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

This is code I'm using to test a webserver on an embedded product that hasn't been behaving well when an HTTP request comes in fragmented across multiple TCP packets:

/* 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.. */

Looking at Wireshark, I see only one TCP packet go out, which contains the entire test header, not the approximately header length / chunk size packets I expect. I have used NoDelay to turn off the Nagle algorithm before, and it usually works just like I expect it to. The online documentation for NoDelay at http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.nodelay%28v=vs.90%29.aspx definitely states "Sends data immediately upon calling NetworkStream.Write" in its associated code sample, so I think I've been using it correctly all this time.

This happens whether or not I step through the code. Is the .NET runtime optimizing away my packet fragmentation?

I'm running x64 Windows 7, .NET Framework 3.5, Visual Studio 2010.

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

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

发布评论

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

评论(4

人疚 2025-01-01 09:17:34

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

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

TcpClient.NoDelay does not mean that blocks of bytes will not be aggregated into a single packet. It means that blocks of bytes will not be delayed in order to aggregate into a single packet.

If you want to force a packet boundary, use Stream.Flush.

人生戏 2025-01-01 09:17:34

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

Grr. It was my antivirus getting in the way. A recent update caused it to start interfering with the sending of HTTP requests to port 80 by buffering all output until the final "\r\n\r\n" marker was seen, regardless of how the OS was trying to handle the outbound TCP traffic. I should have checked that first, but I've been using this same antivirus program for years and never had this problem before, so I didn't even think of it. Everything works just the way it used to when I disable the antivirus.

望喜 2025-01-01 09:17:34

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

The MSDN docs show setting the TcpClient.NoDelay = true, not the TcpClient.Client.NoDelay property. Did you try that?

嗼ふ静 2025-01-01 09:17:34

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

读取 HTTP 时通常读取由几个阶段组成:读取 HTTP 行、读取 HTTP 标头、读取 HTTP 内容(如果适用)。前两部分没有任何大小规范,但有特殊分隔符 (CRLF)。

这里是一些如何读取和解析 HTTP 的信息。

Your test code is just fine (I assume that you send valid HTTP). What you should check is why TCP server is not behaving well when reading from TCP connection. TCP is a stream protocol - that means you cannot make any assumptions on the size of data packets unless you explicitly specify those sizes in your data protocol. For instance you can prefix all your data packets using fixed-size (2 bytes) prefix, that will contain the size of the data to be received.

When reading HTTP usually read is made of several phases: read HTTP line, read HTTP headers, read HTTP content (if applicable). First two parts do not have any size specifications, but they have special delimiter (CRLF).

Here is some info how HTTP can be read and parsed.

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