从三年前第一次接触TCP backlog开始,TCP建连时到底时两个队列还是一个队列就一直作为一个问题存在脑子了,没想到三年过去了才终于搞明白。
上图摘自«TCP/IP详解卷1»关于backlog的描写,我到现在也没有明白这段话想精确表达的含义。
无论如何,希望大家尽量去读英文书,搜英文资料,避免吃屎。
原理 首先看一下经典老图, 第一个问题到底是一个队列还是两个队列
一个队列: 此场景下要将处于SYNC_RECV和ESTABLISHED的状态全部放入其中
两个队列: SYNC_RECV一个队列,ESTABLISHED一个队列
准确来说两种实现都是正确的,因为这不属于TCP协议的范畴。
BSD选择了第一种,当队列满时,仅仅是丢弃收到的SYN,让客户端重试。
Linux2.2之后选择了第二种,存在两个队列。因此对于绝大多数程序员来说,记住下图就可以应用100%的场景了。
When SYN Queue is Full
if net.ipv4.tcp_syncookies=0, 丢弃SYN if net.ipv4.tcp_syncookies=1, if ACP Queue is Full and req_young_len > 1,丢弃SYN。req_young_len是指SYN队列中没有被重传的SYN/ACK pakcet的数量 否则对这个SYNC packet生成syncookies。 When Accept Queue is Full
if tcp_abort_on_overflow=1, 返回 RST packet,并且从SYN Queue中移除。 if tcp_abort_on_overflow=0, 仅仅标记此连接为acked,并不从SYN Queue中移除。一段时间后,服务端会因为[假装]没有收到ACK而重发SYN+ACK packet.