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

2023-04-23 11:04:25 +08:00
 wtmlmz

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

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

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

因此,当 TCP 接收方的队列已满时,发送方会继续发送数据,但这些数据将被丢弃,直到接收方能够接受更多数据。这样可以避免网络拥塞,并确保数据传输的可靠性。
handshake
2023-04-23 11:53:03 +08:00
满了就只能丢弃,这样发送方的拥塞控制机制才会知道丢包了,等待重发;如果发送 RST 就直接断了
handshake
2023-04-23 11:54:11 +08:00
满了就只能丢弃,这样发送方的拥塞控制机制才会知道丢包了,等待重发;如果发送 RST 就直接断了,所以 RST 只有新建立的连接才会收到
artnowben
2023-04-23 12:00:35 +08:00
这个与实现是很相关的,一般如果接收缓冲区满了,可以回一个 ACK ,而不是 RST 。
如果对这些实现细节感兴趣可以看看 freebsd 的实现,小型的实现可以看看 dperf https://github.com/baidu/dperf
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
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 还没完成。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/934712

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX