Post content
这个问题是 Leon Hwang 在他频道里讨论的,我整理成下面的形式。 server.py import socket, time s = socket.socket() s.bind(("127.0.0.1", 9999)) s.listen(1) conn, addr = s.accept() time.sleep(1) conn.send(b'a') time.sleep(1) print(conn.recv(1)) print(conn.recv(1)) conn.close() client.py import socket c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) c.connect(("127.0.0.1", 9999)) c.close() 问服务端会两次 recv 会返回什么。 这里的复杂性在于服务端调用 recv 的时候,socket 先后收到了一个 fin 和一个 rst,目前内核 (6.14.0-29) 的表现是两次 recv 都返回 "" 即 fin 的语义,也就是说用户态永远也不可能知道对端发送了 rst。这导致了 Leon 在他生产环境遇到了问题,用户态读到了 fin,不认为这是什么异常,tcp 本来就允许保持单向打开,所以继续持有 fd;然而这个 socket 实际上已经收到了 rst,但用户态却无法知道,这导致了 tcp 连接泄露。 gpt-5.1 thinking 还在给我杠,说不会收到 rst,我抓包如下 10:02:57.750197 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [S], seq 2552411982, win 65495, options [mss 65495,sackOK,TS val 1139167411 ecr 0,nop,wscale 7], length 0 10:02:57.750225 lo In IP 127.0.0.1.9999 > 127.0.0.1.49768: Flags [S.], seq 2409881948, ack 2552411983, win 65483, options [mss 65495,sackOK,TS val 1139167411 ecr 1139167411,nop,wscale 7], length 0 10:02:57.750251 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [.], ack 1, win 512, options [nop,nop,TS val 1139167411 ecr 1139167411,exp-2333,nop,nop], length 0 10:02:57.750290 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [F.], seq 1, ack 1, win 512, options [nop,nop,TS val 1139167411 ecr 1139167411], length 0 10:02:57.752101 lo In IP 127.0.0.1.9999 > 127.0.0.1.49768: Flags [.], ack 2, win 512, options [nop,nop,TS val 1139167413 ecr 1139167411,exp-2333,nop,nop], length 0 10:02:58.751671 lo In IP 127.0.0.1.9999 > 127.0.0.1.49768: Flags [P.], seq 1:2, ack 2, win 512, options [nop,nop,TS val 1139168412 ecr 1139167411,exp-2333,nop,nop], length 1 10:02:58.751738 lo In IP 127.0.0.1.49768 > 127.0.0.1.9999: Flags [R], seq 2552411984, win 0, length 0 没来记得读 rfc,但隐约觉得似乎有点问题? (先继续做 slides,来不及了,要被开除了,如果哪位老师有什么想法或者我有哪里搞错了欢迎指出 🥹)