我将 tcp 用于非常多的小型发送,我应该关闭 Nagles 算法吗? (人们也将其称为 TCP_NODELAY)

Posted

技术标签:

【中文标题】我将 tcp 用于非常多的小型发送,我应该关闭 Nagles 算法吗? (人们也将其称为 TCP_NODELAY)【英文标题】:I'm using tcp for very many small sends, should I turn off Nagles algorithm? (People also know this as TCP_NODELAY) 【发布时间】:2011-06-01 21:05:04 【问题描述】:

我重发了这篇文章,因为我的标题选择太糟糕了,对此感到抱歉。我的新帖子可以在这里找到:After sending a lot, my send() call causes my program to stall completely. How is this possible?

非常感谢大家。问题是客户端实际上是机器人,他们从不从连接中读取。 (感觉很傻)

【问题讨论】:

你可以简单地编辑你的标题,你知道的。 哈哈,我试过了,但我想不通。我更喜欢那个:/。 【参考方案1】:

Nagle 不会导致“消失在内核中”,这就是为什么禁用它对您没有帮助。 Nagle 只会缓冲一段时间的数据,但最终会在没有用户提示的情况下发送数据。

还有其他罪魁祸首。


编辑更新的问题。

您必须确保客户端正在接收所有发送的数据,并且它正在快速接收数据。让每个客户端写入日志或进行验证。

例如,如果客户端正在等待服务器接受它的 23 字节更新,那么它可能没有接收到数据。这可能会导致服务器的发送缓冲区被填满,从而导致降级并最终导致死锁。

如果这确实是罪魁祸首,解决方案将是一些异步通信,例如 Boost 的 Asio 库。

【讨论】:

是的,我就是这么想的。不过我真的一无所知。我一直在看的东西可能是 tcp 缓冲区大小......我真的不知道 -_- @returneax 您能否修改您的问题以包含您用于在客户端和服务器上发送/接收数据的代码?我想知道您是否正在做一些导致死锁等的事情。 当然,客户端是用 C# 编写的,我的朋友正在编写它,但现在我可以给你服务器代码。服务器也是多线程的... 多线程是相当简单的。这是两个通过消息队列进行通信的线程。第一个线程只是在端口 3500 上侦听新连接。然后它验证他们的用户名和密码创建一个客户端对象并填写其数据,然后通过消息队列将指向该对象的指针作为字节数组传递。因此,当没有人连接登录线程时,accept() 被阻塞。 @return 我更新了我的答案,但现在我看到 Nikolai 打败了我。【参考方案2】:

如果send() 在 TCP 套接字上阻塞,则表明发送缓冲区已满,进而表明连接另一端的对等方读取数据的速度不够快。也许那个客户完全卡住了,没有经常打电话给recv()

【讨论】:

【参考方案3】:

TCP_NODELAY 可能有助于小数据包从发送方到接收方的延迟,但您给出的描述指向不同的方向。我可以想象以下内容:

发送的数据多于接收者实际消耗的数据 - 这最终会溢出发送者的缓冲区 (SO_SNDBUF) 并导致服务器进程在 send(2) 系统调用中出现“卡住”。此时内核等待另一端确认一些未完成的数据,但接收方并不期望它,所以它没有recv(2)

可能还有其他解释,但不看代码很难说。

【讨论】:

您好 Nikolai,我知道客户从不读取数据这一事实。客户端正在由另一个程序模拟。如果他们从不接收数据会导致我自己的缓冲区溢出吗? 转念一想,看来 UDP 可能更适合您的需求。

以上是关于我将 tcp 用于非常多的小型发送,我应该关闭 Nagles 算法吗? (人们也将其称为 TCP_NODELAY)的主要内容,如果未能解决你的问题,请参考以下文章

发送长 TCP 段时会发生啥?

我应该使用 TCP 还是 UDP? [关闭]

Win7机器上没有兑现TCP缓冲区参数

关于tcp半关闭的问题

TCP Socket 不接收数据,写入/发送不超时?

用于嵌入式系统的小型 libc [关闭]