最近由于要在产品上使能TCP的keepalive功能,接合TCPIP详解V2,看了一下它的实现。实现的代码主要集中在tcp_timer_keep()函数中。主要的代码如下:
- delta = TICKS - tp->t_rcvtime;
-
keeptime = tcp_keepidle;
-
-
if (delta < (ULONG)keeptime) {
-
keeptime = keeptime - delta;
-
goto out;
-
}
-
-
if ((priv_always_keepalive ||
-
tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) &&
-
tp->t_state <= TCPS_CLOSING) {
-
if (delta >= tcp_keepidle + tcp_maxidle)
-
goto dropit;
-
-
tcpStat.tcps_keepprobe++;
-
-
templateMbuf = tcp_maketemplate (tp);
-
if (templateMbuf != NULL)
-
t_template = mtod (templateMbuf, struct tcptemp *);
-
if (t_template) {
-
tcp_respond(tp, t_template->tt_ipgen,
-
&t_template->tt_t, (struct mbuf *)NULL,
-
tp->rcv_nxt, tp->snd_una - 1, 0);
-
m_free (templateMbuf);
-
}
-
-
keeptime = tcp_keepintvl;
-
}
-
-
callout_reset(tp->tt_keep, keeptime, tcp_timer_keep, tp);
-
splx(s);
代码简介:对于已经建立的连接,tcp_keepidle时间运行一次keepalive的检查(全局keepalive打开或者socket上的keepalive打开),如果idle的时间超过tcp_keepidle就会发送keepalive的probe消息,如果tcp_keepidle+tcp_maxidle时间还没有接收到数据,则关闭连接)。tcp_maxidle是按照tcp_keepintvl发送包,一连9个包,都没有收到响应的时间。上面代码中delta就是实际的idle时间。
probe包的方式是给对方发送序列号落在对方接收窗口之外的tp->snd_una-1的0长度数据包,导致对方肯定要回答一个ACK(如果连接还活着)或者RST(如果对方已经复位过了)。
阅读(3823) | 评论(0) | 转发(0) |