
当 tcp 接受方的半连接和全连接队列满的时候,发送方再发送数据为什么会丢包,而不是返回 RST 呢?
1 ohwind 2023-04-23 11:06:41 +08:00 By ChatGPT: 当 TCP 接受方的半连接队列和全连接队列都满了,而发送方继续发送数据时,TCP 接受方将不再向发送方发送 ACK 确认消息。因为 TCP 使用滑动窗口协议,它依赖于接收方发送 ACK 确认消息来告诉发送方有多少数据已经被成功接收。如果接收方不再发送 ACK 确认消息,发送方会认为接收方已经收到了所有数据,并且没有发生丢失,因此发送方不会发送 RST 消息。 当发送方继续发送数据时,这些数据将继续填满网络缓冲区。一旦缓冲区已满,新的数据包将被丢弃。这是因为 TCP 协议有一个拥塞控制机制,它会根据网络的拥塞程度来控制发送方的数据发送速率。当网络拥塞时,TCP 会减慢发送速度以避免进一步的网络拥塞。当缓冲区已满时,这被视为一种拥塞迹象,TCP 会将其解释为网络拥塞,并将减慢发送速度。 因此,当 TCP 接收方的队列已满时,发送方会继续发送数据,但这些数据将被丢弃,直到接收方能够接受更多数据。这样可以避免网络拥塞,并确保数据传输的可靠性。 |
2 handshake 2023-04-23 11:53:03 +08:00 满了就只能丢弃,这样发送方的拥塞控制机制才会知道丢包了,等待重发;如果发送 RST 就直接断了 |
3 handshake 2023-04-23 11:54:11 +08:00 满了就只能丢弃,这样发送方的拥塞控制机制才会知道丢包了,等待重发;如果发送 RST 就直接断了,所以 RST 只有新建立的连接才会收到 |
4 atnowben 2023-04-23 12:00:35 +08:00 这个与实现是很相关的,一般如果接收缓冲区满了,可以回一个 ACK ,而不是 RST 。 如果对这些实现细节感兴趣可以看看 freebsd 的实现,小型的实现可以看看 dperf https://github.com/baidu/dperf |
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 |
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 还没完成。 |