为什么 TCP 允许 ACK 值和发送时不一致? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
iqoo
V2EX    程序员

为什么 TCP 允许 ACK 值和发送时不一致?

  •  
  •   iqoo 2022-10-24 20:15:03 +08:00 2902 次点击
    这是一个创建于 1087 天前的主题,其中的信息可能已经有所发展或是发生改变。

    ...

    [发送者 -> 接收者] seq=8000 ack=50

    [发送者 -> 接收者] seq=9000 ack=50

    [接收者 -> 发送者] seq=50 ack=8700 (小于发送者的边界值)

    正常情况下,接收者的协议栈会发送 seq=9000 ,确认收到,并让对方发送后续数据。

    但事实上回复的 ack 值小于 9000 ,对方也会继续发送。虽然很久之前就知道这个特性,并且该特性会带来不少安全问题,但不知为何要这样设计,而且至今很多系统仍支持。

    12 条回复    2022-10-25 13:37:03 +08:00
    tftk
        1
    tftk  
       2022-10-24 20:49:34 +08:00
    确定后面没有 ack 了或者没有丢包吗
    Chieh
        2
    Chieh  
       2022-10-24 21:37:57 +08:00
    正常情况下,接收者应该发送 seq=ack 吧
    wangyu17455
        3
    wangyu17455  
       2022-10-24 22:04:17 +08:00
    发送方没触及发送窗口右边界和接收方接收窗口中较小的那个就会一直发送,收到 ack 会导致发送窗口右移,只要发送窗口右边界大于 9000 就会继续发送
    lysS
        4
    lysS  
       2022-10-24 22:55:09 +08:00
    安全问题是啥? tcp 也不是安全的吧?
    proxytoworld
        5
    proxytoworld  
       2022-10-24 23:58:15 +08:00
    没有到临界值把,等差值到了临界值就会少发
    bantianys
        6
    bantianys  
       2022-10-25 07:19:23 +08:00
    建议确认下对应的发送包和接受包对应关系,可以参考下 wireshark 抓包界面的 symbol 。
    参考 https://www.wireshark.org/docs/wsug_html_chunked/ChUsePacketListPaneSection.html

    Table 3.16. Related packet symbols
    参考 The selected packet acknowledges this packet 图标
    Panic
        7
    Panic  
       2022-10-25 08:53:35 +08:00
    因为 tcp 是 stream 类型的,stream ,stream ,stream 。
    字节流本来就允许这样的啊。
    zhs227
        8
    zhs227  
       2022-10-25 09:34:14 +08:00
    链路上有包正在传送,称为 in flight 。如果发一个,ack 了再发下一个,那路上永远只有 1 个包大小的数据。无法有效利用带宽。1 个包的 size / rtt ,你猜能达到多高的传送带宽。

    如果收到 ack 小于当前发送的最后包,发送端就不再发送,相当于把窗口彻底去掉了,不清楚你说的带来不少安全问题是什么安全问题。

    如果全世界都错了,……
    iqoo
        9
    iqoo  
    OP
       2022-10-25 11:21:57 +08:00
    @zhs227 合法的 ACK 值是 8000 或 9000 ,是已发送的 SEQ 中的某一个,而不该是 8700 这个中间值。除非是链路中的设备把原先的包拆分了。
    zhs227
        10
    zhs227  
       2022-10-25 11:39:09 +08:00
    tcp 是 stream,没有边界的。 你调用 tcp 的 send 函数不是按包发送,只是进入操作系统缓冲区,然后缓冲区再分段向外发送。操作系统向外发送的分段不一定与上层调用 send 是一致的。比如说你调用 send 每次发送包长是 9000 字节,但是网络上的 MTU 只有 1500 ,它就会分成很多个包。所以没有“合法”的 ack 值的说法
    nVic
        11
    nVic  
       2022-10-25 13:25:47 +08:00
    JohnBull
        12
    JohnBull  
       2022-10-25 13:37:03 +08:00
    问题是"为什么不允许呢?"
    TCP 的 ACK 的含义本来很简单:"我已经成功收到了你的第 8700 字节,请从 8701 字节继续发"
    作为面向字节流的协议设计,语义简洁而明确. 如果引入了与发送分包相关的限制就是无事生非了,让人根本没法实现

    出现这种问题的直接原因不清楚, 最有可能是接收方的缓冲区只够接收到 8700 字节了.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2958 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 47ms UTC 13:45 PVG 21:45 LAX 06:45 JFK 09:45
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86