把握手状态编进序号,让服务器越过队列直接应答。

SYN Cookie 在队列溢出时作答

监听套接字维护的是两个队列,不是一个。半开连接先待在 SYN 队列里,直到客户端的最后一个 ACK 到达;握手完成的连接随后进入 accept 队列,等着应用调用 accept()。两者各有各的上限,而究竟是哪一个溢出,决定了客户端体验到什么。 SYN Cookie 是为第一个队列准备的。它满了以后,服务器不再分配状态,转而把稍后需要的东西编进序号里,于是握手在零内存占用下完成。这确实是一次救援,同时也是一次降级:被救下来的那条连接,比正常情况下本该建立的那条更差。 两个队列,两种症状 一个 SYN 会分配一个 request socket,把连接推进 SYN_RECV 并回一个 SYN-ACK。客户端的 ACK 再把它移进 accept 队列、状态变成 ESTABLISHED。SYN 队列由 tcp_max_syn_backlog 按监听套接字限流——最小值 128,随内存放大,每个表项大约占 304 字节。accept 队列的上限来自 somaxconn(当前内核默认 4096,Linux 5.4 之前是 128),再与应用程序传给 listen() 的 backlog 共同起作用。 两种溢出长得完全不一样。SYN 队列溢出正是 syncookie 为之而生的场景:连接照样能完成。accept 队列溢出更糟也更安静——在 tcp_abort_on_overflow 取默认值 0 的情况下,服务器直接忽略那个最后的 ACK,于是 connect() 返回成功,客户端把请求发出去,然后再也等不到任何回应。实测:backlog 设为 1、客户端 400 个,400 个全都以为自己连上了,服务器实际只能接受 3 个,另外 397 个在两端都没有任何报错的情况下丢掉了。 ...

十月 30, 2027 · 2 分钟 · XB Field Notes