当 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
artnowben 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 还没完成。 |