
...
[发送者 -> 接收者] seq=8000 ack=50
[发送者 -> 接收者] seq=9000 ack=50
[接收者 -> 发送者] seq=50 ack=8700 (小于发送者的边界值)
正常情况下,接收者的协议栈会发送 seq=9000 ,确认收到,并让对方发送后续数据。
但事实上回复的 ack 值小于 9000 ,对方也会继续发送。虽然很久之前就知道这个特性,并且该特性会带来不少安全问题,但不知为何要这样设计,而且至今很多系统仍支持。
1 tftk 2022 年 10 月 24 日 确定后面没有 ack 了或者没有丢包吗 |
2 Chieh 2022 年 10 月 24 日 正常情况下,接收者应该发送 seq=ack 吧 |
3 wangyu17455 2022 年 10 月 24 日 发送方没触及发送窗口右边界和接收方接收窗口中较小的那个就会一直发送,收到 ack 会导致发送窗口右移,只要发送窗口右边界大于 9000 就会继续发送 |
4 lysS 2022 年 10 月 24 日 安全问题是啥? tcp 也不是安全的吧? |
5 proxytoworld 2022 年 10 月 24 日 没有到临界值把,等差值到了临界值就会少发 |
6 bantianys 2022 年 10 月 25 日 建议确认下对应的发送包和接受包对应关系,可以参考下 wireshark 抓包界面的 symbol 。 参考 https://www.wireshark.org/docs/wsug_html_chunked/ChUsePacketListPaneSection.html Table 3.16. Related packet symbols 参考 The selected packet acknowledges this packet 图标 |
7 Panic 2022 年 10 月 25 日 因为 tcp 是 stream 类型的,stream ,stream ,stream 。 字节流本来就允许这样的啊。 |
8 zhs227 2022 年 10 月 25 日 链路上有包正在传送,称为 in flight 。如果发一个,ack 了再发下一个,那路上永远只有 1 个包大小的数据。无法有效利用带宽。1 个包的 size / rtt ,你猜能达到多高的传送带宽。 如果收到 ack 小于当前发送的最后包,发送端就不再发送,相当于把窗口彻底去掉了,不清楚你说的带来不少安全问题是什么安全问题。 如果全世界都错了,…… |
9 iqoo OP @zhs227 合法的 ACK 值是 8000 或 9000 ,是已发送的 SEQ 中的某一个,而不该是 8700 这个中间值。除非是链路中的设备把原先的包拆分了。 |
10 zhs227 2022 年 10 月 25 日 tcp 是 stream,没有边界的。 你调用 tcp 的 send 函数不是按包发送,只是进入操作系统缓冲区,然后缓冲区再分段向外发送。操作系统向外发送的分段不一定与上层调用 send 是一致的。比如说你调用 send 每次发送包长是 9000 字节,但是网络上的 MTU 只有 1500 ,它就会分成很多个包。所以没有“合法”的 ack 值的说法 |
11 nVic 2022 年 10 月 25 日 |
12 JohnBull 2022 年 10 月 25 日 问题是"为什么不允许呢?" TCP 的 ACK 的含义本来很简单:"我已经成功收到了你的第 8700 字节,请从 8701 字节继续发" 作为面向字节流的协议设计,语义简洁而明确. 如果引入了与发送分包相关的限制就是无事生非了,让人根本没法实现 出现这种问题的直接原因不清楚, 最有可能是接收方的缓冲区只够接收到 8700 字节了. |