问题描述
我在 C# 中有一个 HTTP 服务器的实现.使用 ab 我发现了一个奇怪的性能问题.每个请求在关闭 Keep-Alive 时需要 5 毫秒,但在开启 Keep-Alive 时需要 40 毫秒!
I have an implementation of an HTTP server in C#.Using ab I discovered a weird performance issue.Each request took 5 ms with Keep-Alive Off but 40 ms with Keep-Alive on!
测试页被生成为单个字节[],使用单个 socket.Send 调用作为回复发送.
The testpage is generated into a single byte[] which get sent as reply using a single socket.Send call.
据我所知,原因是 TCP 堆栈中使用的 Nagle 算法.
The cause is as far as I can tell Nagle's algorithm used in the TCP stack.
到目前为止,我使用的是 NoDelay 属性在每个服务的 HTTP 请求的末尾.
So far I am using the NoDelay property in the end of every HTTP request served.
socket.NoDelay = true;
socket.NoDelay = false;
现在确实解决了问题.但我没有任何文件来支持我的发现.
Which does solve the problem for now. But I have no documentation to backup my discovery.
这是在 linux/mono 系统上测试的.
This was tested on a linux/mono system.
是否有刷新 TCP 连接的标准方法?
这个答案 正在解决同样的问题.这里的不同之处在于我只想暂时禁用算法.
This answer is addressing the same issue. The difference here is that I am looking to only temporarily disabling the algorithm.
推荐答案
我用 Wireshark 对此进行了测试.不幸的是,
I tested this with Wireshark. Unfortunately,
socket.NoDelay = true;
socket.NoDelay = false;
没有效果.同样,
socket.NoDelay = true;
socket.Send(new byte[0]);
socket.NoDelay = false;
也没有效果.从观察到的行为来看,NoDelay
属性似乎只影响下一次使用非空缓冲区调用 Send
.换句话说,您必须在 NoDelay
生效之前发送一些实际数据.
also has no effect. From observed behaviour, it appears that the NoDelay
property only affects the next call to Send
with a non-empty buffer. In other words, you have to send some actual data before NoDelay
will have any effect.
因此,我得出的结论是,如果您不想发送任何额外的数据,则无法显式刷新套接字.
Therefore, I conclude that there is no way to explicitly flush the socket if you don’t want to send any extra data.
但是,由于您正在编写 HTTP 服务器,因此您可以使用一些技巧:
However, since you are writing an HTTP server, you may be able to use a few tricks:
- 对于使用
Transfer-Encoding: chunked
服务的请求,您可以发送流结束标记("0"
) 和NoDelay = true
. - 如果您从本地文件系统提供文件,您将知道文件何时结束,因此您可以在发送最后一个块之前设置
NoDelay = true
. - 对于使用
Content-Encoding: gzip
服务的请求,您可以在关闭 gzip 流之前设置NoDelay = true
;gzip 流将在实际完成和关闭之前发送一些最后的位.
- For requests that are served using
Transfer-Encoding: chunked
, you can send the end-of-stream marker (the"0"
) withNoDelay = true
. - If you are serving a file from the local filesystem, you will know when the file ends, so you could set
NoDelay = true
just before sending the last chunk. - For requests that are served using
Content-Encoding: gzip
, you can setNoDelay = true
just before closing the gzip stream; the gzip stream will send some last bits before actually finishing and closing.
我现在肯定要把上面的内容添加到我的 HTTP 服务器:)
I’m certainly going to add the above to my HTTP server now :)
这篇关于插座“冲洗"通过暂时启用 NoDelay的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!