最新公告
  • 欢迎您光临波比源码,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入我们
  • Linux下关于TCP的keep alive的实现源码分析


     TCP下的Keep Alive

    我们常说的TCP的keep alive,就是为了保证连接的有效性,在间隔1定的时间发探测包,根据回复来确认该连接是不是有效。通常上层利用会自己提供心跳检测机制,而Linux内核本身也提供了从内核层面的确保连接有效性的方式。

    在sock 函数中可以设置是不是需要打开keep alive开关,默许建立socket 是关闭keep alive的。代码以下

    optval = 1;
    optlen = sizeof(optval);
    if(setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
    perror("setsockopt()");
    close(s);
    exit(EXIT_FAILURE);
    }

    Keep Alive 的控制参数

    tcp_keepalive_time 参数

    控制keep alive的最长空闲时间

    tcp_keepalive_probes 参数

    当超过最长空间时间后,内核会尝试发出探测包确认客户端时候存活,该参数控制的是尝试的次数

    tcp_keepalive_intvl 参数

    当超过最长空闲时间后,内核会发出探测包,当没有收到确认回复的,该参数控制下个探测包的时间

    Linux下如何实现Keep Alive

    sock结构体中的timer_list

    在sock结构体中,存在timer_list的结构体sk_timer,参考下面结构

    struct sock{

    struct timer_list sk_timer;

    }
    struct timer_list {
    struct list_head entry;
    unsigned long expires;

    void (*function)(unsigned long);
    unsigned long data;

    struct tvec_base *base;
    #ifdef CONFIG_TIMER_STATS
    void *start_site;
    char start_comm[16];
    int start_pid;
    #endif
    #ifdef CONFIG_LOCKDEP
    struct lockdep_map lockdep_map;
    #endif
    };

    timer_list结构体,是在sock里经常使用的timer履行链表,entry代表的是链表的头, expires代表的失效时间,而function就是履行的函数。

    注册keepalive处理函数

    void inet_csk_init_xmit_timers(struct sock *sk,
    void (*retransmit_handler)(unsigned long),
    void (*delack_handler)(unsigned long),
    void (*keepalive_handler)(unsigned long))
    {
    struct inet_connection_sock *icsk = inet_csk(sk);

    setup_timer(&icsk->icsk_retransmit_timer, retransmit_handler,
    (unsigned long)sk);
    setup_timer(&icsk->icsk_delack_timer, delack_handler,
    (unsigned long)sk);
    setup_timer(&sk->sk_timer, keepalive_handler, (unsigned long)sk);//注册了函数在sk_timer中
    icsk->icsk_pending = icsk->icsk_ack.pending = 0;
    }

    当连接完成的时候(也就是握手成功的时候),在新生成的sock里面的sk_timer结构体中,注册了函数keepalive_handler函数

    void tcp_init_xmit_timers(struct sock *sk)
    {
    inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer,
    &tcp_keepalive_timer);
    }

    而keepalive_handler函数就是tcp_keepalive_timer函数

    static void tcp_keepalive_timer (unsigned long data)
    {
    ……

    if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE)
    goto out;

    elapsed = keepalive_time_when(tp);

    /* It is alive without keepalive 8) */
    if (tp->packets_out || tcp_send_head(sk))
    goto resched;

    elapsed = tcp_time_stamp – tp->rcv_tstamp;

    if (elapsed >= keepalive_time_when(tp)) {
    if (icsk->icsk_probes_out >= keepalive_probes(tp)) {
    tcp_send_active_reset(sk, GFP_ATOMIC);
    tcp_write_err(sk);
    goto out;
    }
    if (tcp_write_wakeup(sk) <= 0) {
    icsk->icsk_probes_out++;
    elapsed = keepalive_intvl_when(tp);
    } else {
    /* If keepalive was lost due to local congestion,
    * try harder.
    */
    elapsed = TCP_RESOURCE_PROBE_INTERVAL;
    }
    } else {
    /* It is tp->rcv_tstamp + keepalive_time_when(tp) */
    elapsed = keepalive_time_when(tp) – elapsed;
    }
    …..
    }

    上面只是截取了1部份代码,重点是前面提到的参数的实现,代码首先先检查了是不是在sock里设置了参数SO_KEEPALIVE,也就是sock里面的flag:SOCK_KEEPOPEN。

    如果设置了socket的SO_KEEPALIVE,才继续检查时间戳,取的上次收到包的时间戳和当前时间戳的差值,进行和参数keepalive_time的比较,如果已超时了,那末检查发已出探测包失败的次数,如果次数已比keepalive_probes的大,那末发出reset包,同时写毛病报告,关闭sock。

     如果比设置的探测包次数小的话,那发出探测包,同时设置下次的校验的时间戳为keepalive_intvl, 而不在是keepalive_time。

    注意:在这里keepalive_intvl只是控制触发下次校验的时间

    计算结束无效连接的时间N会有两种情况

    a.  keepalive_intvl 的时间比 keepalive_time 大

    N=keepalive_time +keepalive_intvl*keepalive_probes

    b. keepalive_intvl 的时间比 keepalive_time小

    N=keepalive_time +keepalive_time*keepalive_probes

    这也就是为何在默许设置里,认为无效的连接的时间实际上是7200*6 要12小时才会断掉连接

    代码中设置keepalive_time,keepalive_probes,keepalive_intvl

    setsockopt(s, SOL_TCP, TCP_KEEPIDLE, &val, sizeof(int))
    setsockopt(s, SOL_TCP, TCP_KEEPINTVL, &val, sizeof(int))
    setsockopt(s, SOL_TCP, TCP_KEEPCNT, &val, sizeof(int))

    所对应的3个参数 TCP_KEEPIDLE  –> keepalive_time, TCP_KEEPINTVL–> keepalive_intvl, TCP_KEEPCNT–> keepalive_probes

    3个参数本身也有最大值的保护,TCP_KEEPIDLE 最大是32767 TCP_KEEPINTVL 最大值是32767 TCP_KEEPCNT 最大值是127
    JAVA中并没有提供对这些参数的修改
    波比源码 – 精品源码模版分享 | www.bobi11.com
    1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
    2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
    3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
    4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
    5. 如有链接无法下载、失效或广告,请联系管理员处理!
    6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
    7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!

    波比源码 » Linux下关于TCP的keep alive的实现源码分析

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    波比源码
    一个高级程序员模板开发平台
    升级波友尊享更多特权立即升级