我观察了在两个不同的 Red Hat 机器上运行的服务器应用程序和客户端之间的 TCP 连接中的以下行为。
示例 1
- 客户端确认到目前为止的所有内容(ACK WND = 1424)
- 服务器向 TCP 层发送 296 个字节,然后发送给客户端(PUSH/ACK)
- 服务器向 TCP 层发送 296 个字节,然后发送给客户端(PUSH/ACK)
- 服务器向 TCP 层发送 296 个字节,然后发送给客户端(PUSH/ACK)
- 服务器发送/尝试发送 239 个字节到 TCP 层,但是:发生以下两种情况之一
- 操作系统等待约 30 毫秒,直到收到客户端的 ACK 后才发送这些字节(此 x 字节发送在下文中将称为延迟消息)
- tcp 发送调用返回 EWOULDBLOUCK 或 EAGAIN(我认为这是不可能的,因为 239+239+239+239 < 1424。如果我错了,请纠正我
示例 2
- 客户端确认到目前为止的所有内容(使用 WND=1424 进行确认)
- 服务器向 TCP 层发送 239 个字节,然后发送给客户端
- 服务器发送/尝试发送 239 个字节到 TCP 层,并且发生上述两种情况之一
我想了解的问题是,当客户端的窗口大小足够大时,为什么服务器应用程序或操作系统要等到 ACK?这是我可以在操作系统级别进行调整的吗?我可以强制服务器发送所有字节,直到客户端的窗口填满吗?
据我了解,有两个可能的原因
- 服务器应用程序不会将“延迟消息”传递到 TCP 级别,因为发送系统调用返回了 EWOULDBLOUCK 或 EAGAIN。
- 应用程序确实将消息传递到 TCP 层,但是操作系统直到收到来自客户端的 ACK 才会发送该消息。
在所有延迟消息场景中,在发送延迟消息之前,客户端都会发送 ACK。此外,应用程序的工作逻辑表明它确实将消息传递到了 TCP 层。
您能否建议我应该重点解决哪里的问题?
- 我可以在客户端或服务器端设置一些操作系统级别的设置吗
- 这是否是应用服务器的故障?
- 我是否错误地认为操作系统直到消息填满窗口才会返回 EWOULDBLOCK
编辑:重复的原因:我不确定问题出在哪里;网络/操作系统。我添加了其他详细信息。此外,我需要从 Linux 的 TCP 实现中获取 POV,所以我认为这个问题应该在这里。
答案1
这称为“延迟 ACK”,这是 TCP 协议的工作方式。请参阅https://en.m.wikipedia.org/wiki/TCP_delayed_acknowledgment了解更多详情。如果该功能影响应用程序的性能,您可以禁用该功能。假设 iSCSI 默认已关闭延迟 ACK。