V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wtmlmz
V2EX  ›  程序员

关于计算机网络 tcp 协议,我有个问题

  •  1
     
  •   wtmlmz · 2023-04-23 11:04:25 +08:00 · 1665 次点击
    这是一个创建于 584 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当 tcp 接受方的半连接和全连接队列满的时候,发送方再发送数据为什么会丢包,而不是返回 RST 呢?

    6 条回复    2023-04-23 16:37:10 +08:00
    ohwind
        1
    ohwind  
       2023-04-23 11:06:41 +08:00
    By ChatGPT:
    当 TCP 接受方的半连接队列和全连接队列都满了,而发送方继续发送数据时,TCP 接受方将不再向发送方发送 ACK 确认消息。因为 TCP 使用滑动窗口协议,它依赖于接收方发送 ACK 确认消息来告诉发送方有多少数据已经被成功接收。如果接收方不再发送 ACK 确认消息,发送方会认为接收方已经收到了所有数据,并且没有发生丢失,因此发送方不会发送 RST 消息。

    当发送方继续发送数据时,这些数据将继续填满网络缓冲区。一旦缓冲区已满,新的数据包将被丢弃。这是因为 TCP 协议有一个拥塞控制机制,它会根据网络的拥塞程度来控制发送方的数据发送速率。当网络拥塞时,TCP 会减慢发送速度以避免进一步的网络拥塞。当缓冲区已满时,这被视为一种拥塞迹象,TCP 会将其解释为网络拥塞,并将减慢发送速度。

    因此,当 TCP 接收方的队列已满时,发送方会继续发送数据,但这些数据将被丢弃,直到接收方能够接受更多数据。这样可以避免网络拥塞,并确保数据传输的可靠性。
    handshake
        2
    handshake  
       2023-04-23 11:53:03 +08:00
    满了就只能丢弃,这样发送方的拥塞控制机制才会知道丢包了,等待重发;如果发送 RST 就直接断了
    handshake
        3
    handshake  
       2023-04-23 11:54:11 +08:00
    满了就只能丢弃,这样发送方的拥塞控制机制才会知道丢包了,等待重发;如果发送 RST 就直接断了,所以 RST 只有新建立的连接才会收到
    artnowben
        4
    artnowben  
       2023-04-23 12:00:35 +08:00
    这个与实现是很相关的,一般如果接收缓冲区满了,可以回一个 ACK ,而不是 RST 。
    如果对这些实现细节感兴趣可以看看 freebsd 的实现,小型的实现可以看看 dperf https://github.com/baidu/dperf
    liuxu
        5
    liuxu  
       2023-04-23 12:16:53 +08:00
    了解下 /proc/sys/net/ipv4/tcp_abort_on_overflow ,默认 0 是 drop 包,置 1 为 rst

    这种情况发生在 server 端进程无法快速消费内核请求队列,内核队列满后:

    server 端内核 drop 包,client 因为没收到回复会重发,重发有时间间隔,server 端再次收到请求时,此时 server 端进程可能已经消费了内核的请求队列,有空余的空间给重发的请求
    server 端内核 rst 包,client 收到 rst 包会直接 close 连接,这样 client 代码需要自己不断重连


    linux 不建议置 1 返回 rst

    https://man7.org/linux/man-pages/man7/tcp.7.html
    linuxyz
        6
    linuxyz  
       2023-04-23 16:37:09 +08:00
    问题可能有点歧义,你这里指已经三次握手完成的 TCP session ? 还是新的 TCP 握手?

    对于已经建立的连接: 如果接收端的缓冲区满了,应该会有 ACK 回应标明 WindowSize 为 0 。
    回 RST 就会导致发送端关闭 TCP session 。但当前的情况仅仅是通信拥塞了而已,在接受端的 App read 了 socket 的数据之后是可以恢复的。

    如果是建立新的 TCP session, 用户的程序 accept 不够快,listen 的半开 socket 队列满了,我感觉应该和实现有关,不过大概率行为应该是啥也不发。毕竟 TCP session 还没完成。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3596 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:51 · PVG 18:51 · LAX 02:51 · JFK 05:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.