zoukankan      html  css  js  c++  java
  • TCP系列10—连接管理—9、syncookie、fastopen与backlog

    这部分内容涉及较多linux实现,可以跳过。

    一、listen系统调用对backlog的处理

    1. 当socket处于LISTEN或者CLOSED状态时,fastopen队列的长度可以通过TCP_FASTOPEN选项进行设置。

    2. 对于listen的入参backlog,内核会限制backlog=min(backlog,/proc/sys/net/core/somaxconn)

    3. 如果当前打开了TFO的server端开关(tcp_fastopen的0x2有效),并且fastopen队列的最大长度还没通过选项设置,此时若tcp_fastopen的0x400有效,则初始化fastopenq.max_qlen=backlog,若tcp_fastopen的0x800有效,则初始化fastopenq.max_qlen=min(backlog,tcp_fastopen>>16)。fastopenq.max_qlen限制了fastopen逻辑队列和fastopen的RST队列的总长度

    4. 更新sk->sk_max_ack_backlog = backlog,sk_max_ack_backlog同时限制了半连接逻辑队列和accept队列的长度


    Accetp队列判断条件是>,半连接逻辑队列和fastopen判断条件是>=


    二、对SYN报文的处理

    1. 当内核编译打开CONFIG_SYN_COOKIES选项的时候,只要满足下面两个条件中的一个则启用syncookie:

      ①、tcp_syncookies为2。

      ②、tcp_syncookies为1,半连接逻辑队列满,SYN报文不是timewait转过来的。

      如果半连接队列满,且这个SYN报文不是timewait转过来的,这种场景下,如果tcp_syncookies=0,则会直接丢掉这个SYN报文。



    2. 如果全连接队列满,并且半连接逻辑队列中还有未重传的synack报文,那么直接丢掉这个syn报文。

    3. 当依据上面判断不需要启用syncookie的时候,则会判断是否使能fastopen,其中当fastopen逻辑队列和fastopen的RST队列总长度超过fastopenq.max_qlen并且fast open的rst队列没有可以释放的节点的时候,则不会启用fastopen。

    4. 如果启动了syncookie,那么req使用后会释放,不会添加到半连接逻辑队列也不会添加到accept队列

    5. 如果启用了fastopen,那么req将会直接添加到accept队列,如果accept队列满,则启动fastopen队列失败。

    6. 如果未启动syncookie也未启用fastopen,那么把req添加到半连接逻辑队列


    三、三次握手最后ACK的处理

    如果在处理SYN报文的时候,启用了syncookie,此时校验syncookie通过,但是accept队列满的时候,丢弃报文。

    fastopen在接收到SYN报文的时候就已经处理了半连接逻辑队列和accept队列。

    如果对应的连接即没有启用syncookie,也没有启用fastopen,那么accept队列满的时候按照如下处理

    tcp_abort_on_overflow=0场景下,直接丢掉这个报文

    tcp_abort_on_overflow=1场景下,回复RST。


    补充:

    另外reqsk_timer_handler重传函数中,如果(qlen << 1) > max(8U,sk_max_ack_backlog),即半连接队列已经使用了一半以上的时候,则会对重传次数进行回退。

    另外还有一个设置参数:tcp_max_syn_backlog,当设置tcp_syncookies=0来关闭syncookie功能的时候,如果半连接请求队列的长度超过了(3/4)*tcp_max_syn_backlog,那么新接收的SYN报文需要在tcp_metric缓存中验证通过后才能接收这个连接,否则直接丢掉SYN报文。


    四、wireshark示例

    1、默认设置下tcp_syncookies=1、tcp_abort_on_overflow=0,listen入参backlog设置为5,场景如下图所示,当启用syncookie的时候,TSval的低四位表示接收到的window scale,第五位表示SACK,第六位表示ECN。

    首先No1、No3、No5、No7、No9五个数据包填满了半连接逻辑队列,因此从下图Timestamp value列可以看到No11、No13、No15、No17启用了syncookie。

    接着No19报文把20001端口对应的连接从半连接队列转移到了accept队列。此时半连接逻辑队列空闲出一个位置。

    No20这个SYN报文对应的req重新添加到了半连接队列,可以从图中看到并没有启用syncookie。

    No22-No25这几个数据包对应的连接之前位于半连接对应,可以被server正常接收处理并建立连接。

    No26:这个对应之前启用了syncookie的No11,因为accept队列满的判断标准是大于等于,因此accept队列相比半连接队列可以多接收一个连接,No26正常建立连接。

    No27、No28、No29、No32:这几个报文同样因为accept队列满而不能建立连接。但是No32报文对应的连接保存于半连接队列中,而No27-No29是通过syncookie响应的SYN报文。至此总共建立了6个连接,对应client端口号为20001-20006。

    接着client尝试发送数据的时候可以看到,对应端口20007-20010的client数据包No43-No46,server端都没有响应,说明连接并没有建立起来。

    No47-No51:因为端口20010的连接存在于半连接队列中,因此会触发synack的重传。而端口20007-20009的连接通过syncookie响应SYN连接请求,并不会触发synack重传。


    2、设置tcp_syncookies=1、tcp_abort_on_overflow=1,重复上面的测试,唯一的差异就在于端口号为20010的连接。如下图所示,因此该连接处于半连接逻辑队列里面,而server端接收到三次握手的ACK报文的时候全连接队列满,因此直接回复RST,abort这个连接。














  • 相关阅读:
    ERRORCODE=4228, SQLSTATE=null
    DB2和Oracle中唯一约束和唯一索引对比
    SW 3D 样条曲线
    SW 快速操作
    spring依赖注入的方式(一)
    Oracle Connect By的用法
    转:min(x,y)高效算法
    【转】QQ盗号核心编程
    转:理解并解决GBK转UTF8奇数中文乱码
    Oracle数据库的导入和导出命令
  • 原文地址:https://www.cnblogs.com/lshs/p/6038508.html
Copyright © 2011-2022 走看看