Post content
发现我最爱的 UNP 关于 tcp socket 如何处理 RST 的描述居然是错的。Linux 处理 tcp reset 是看链接状态的: void tcp_reset(struct sock *sk) { trace_tcp_receive_reset(sk); /* We want the right error as BSD sees it (and indeed as we do). */ switch (sk->sk_state) { case TCP_SYN_SENT: sk->sk_err = ECONNREFUSED; break; case TCP_CLOSE_WAIT: sk->sk_err = EPIPE; break; case TCP_CLOSE: return; default: sk->sk_err = ECONNRESET; } ... 所以有以下三种典型情况: 1. 主动连接方发送 tcp syn,对端并没有监听目标端口,返回 tcp reset,connect syscall 返回 ECONNREFUSED 即 connection refused. 2. 主动关闭方先发一个 fin,被动关闭方收到 fin 之后继续发送 tcp payload,这是合法的 tcp 半关闭单向通道;被动关闭方第一次 send 会成功发送,但主动端如果已经 **全关闭**,会返回 tcp reset;被动方收到 reset 后第二次 send 会返回 EPIPE 并伴随 SIGPIPE。 3. 主动关闭方由于一些原因(linger、 非空 recvbuf on close)直接发送 tcp reset,被动方的 send syscall 会直接返回 ECONNRESET。write syscall 也会 ECONNRESET,但要注意 tcp reset 也是入 recvbuf 的,必须先消费掉 payload。 UNP 只描述了场景2,但是 1 和 3 其实也很常见,而且 2 和 3 很容易混淆,本频道之前讨论过几次 tcp reset / SIGPIPE 就完全稀里糊涂。虽然区分出来好像也没特别大的帮助,但给人一种很专业的样子😎