TCP协议详解-定时器

3. TCP定时器

3.1 连接建立(connection establishment)定时器

        这个定时器由TCP_KEEP计数器实现

/*

* Keep-alive timer went off; send something

* or drop connection if idle for too long.

*/

case TCPT_KEEP:

tcpstat.tcps_keeptimeo++;

 if (tp->t_state < TCPS_ESTABLISHED)

 goto dropit;

......

dropit:

tcpstat.tcps_keepdrops++;

tp = tcp_drop(tp, ETIMEDOUT);

 break;

......

        如代码所示,如果tcp的state<ESTABLISHED,表明其处于连接建立状态。定时器超时后,调用dropit终止连接。大多数伯克利系统将建立一个连接的最长时间设置为75s。连接建立定时器配合重传定时器一起使用,重传定时器会隔一段时间重传SYN,如下图所示:

        图中可以看出,对于一个新连接,重传定时器初始化为6s,后续值为24s和48s。重传定时器在0s,6s和30s处传送SYN报文。在75s处,连接定时器超时,调用tcp_drop()终止连接。

3.2 保活(keepalive)定时器

        TCP_KEEP同时也实现了保活定时器。代码如下(4.4BSD-Lite2):

case TCPT_KEEP:

tcpstat.tcps_keeptimeo++;

 if (tp->t_state < TCPS_ESTABLISHED)

 goto dropit;

 if (tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE &&

tp->t_state <= TCPS_CLOSE_WAIT) {

 if (tp->t_idle >= tcp_keepidle + tcp_maxidle)

 goto dropit;

 /*

* Send a packet designed to force a response

* if the peer is up and reachable:

* either an ACK if the connection is still alive,

* or an RST if the peer has closed the connection

* due to timeout or reboot.

* Using sequence number tp->snd_una-1

* causes the transmitted zero-length segment

* to lie outside the receive window;

* by the protocol spec, this requires the

* correspondent TCP to respond.

*/

tcpstat.tcps_keepprobe++;

        保活定时器的作用和应用层的心跳类似。检测对端tcp连接是否存在。其发送的序号为tcp->snd_una-1,这样就发送了一个0字节的报文段,从而来检测对端tcp连接的情况。所有的保活定时器在连接2小时候空闲后超时。然后以75s为间隔连续发送9个探测报文段。如果皆无响应,则丢弃此连接。所以一共是2小时+75s * 9后(大约为2个小时11分钟),关闭连接。如下图所示:

3.3 重传(retransmission)定时器

        重传定时器的取值依赖于连接上测算得到的RTT(RTT测算方法不在本次讨论范围内)。         代码如下:

case TCPT_REXMT:

 if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {

tp->t_rxtshift = TCP_MAXRXTSHIFT;

tcpstat.tcps_timeoutdrop++;

tp = tcp_drop(tp, tp->t_softerror ?

tp->t_softerror : ETIMEDOUT);

 break;

 }

tcpstat.tcps_rexmttimeo++;

rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];

TCPT_RANGESET(tp->t_rxtcur, rexmt,

tp->t_rttmin, TCPTV_REXMTMAX);

tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;

 /*

* If losing, let the lower level know and try for

* a better route. Also, if we backed off this far,

* our srtt estimate is probably bogus. Clobber it

* so we'll take the next rtt measurement as our srtt;

* move the current srtt into rttvar to keep the current

* retransmit times until then.

*/

 if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {

in_losing(tp->t_inpcb);

tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);

tp->t_srtt = 0;

 }

tp->snd_nxt = tp->snd_una;

 ......

 (void) tcp_output(tp);

 break;
  • 重传移位计数器(t_rxtshift)在每次重传时递增,如果大于TCP_MAXRXTSHIFT(12),连接将被丢弃。
  • 代码中的TCP_REXMTVAL宏是为了实现指数退避,即重传超时时间逐渐变为1.5、3、6、12、24、48、64、64、64、64、64、64、64(s)。
  • 如果报文段重传次数>3次(TCP_MAXRXTSHIFT(12)/4),则会释放缓存中的路由以便重新寻找新的路由。
  • 最后强迫重传最早的未确认的数据:
tp->snd_nxt = tp->snd_una;//下一个序号snd_nxt被置为最早的未确认过的报文

(void) tcp_output(tp);//强制发送

        重传过程如下图所示:

3.4 持续(persist)定时器

        持续定时器超时后,由于对端已通告接收窗口为0,则强制发送1字节的数据以探测对端窗口。 代码如下所示:

/*

* Persistance timer into zero window.

* Force a byte to be output, if possible.

*/

 case TCPT_PERSIST:

tcpstat.tcps_persisttimeo++;

 /*

* Hack: if the peer is dead/unreachable, we do not

* time out if the window is closed. After a full

* backoff, drop the connection if the idle time

* (no responses to probes) reaches the maximum

* backoff that we would use if retransmitting.

*/

 if (tp->t_rxtshift == TCP_MAXRXTSHIFT &&

 (tp->t_idle >= tcp_maxpersistidle ||

tp->t_idle >= TCP_REXMTVAL(tp) * tcp_totbackoff)) {

tcpstat.tcps_persistdrop++;

tp = tcp_drop(tp, ETIMEDOUT);

 break;

 }

tcp_setpersist(tp);

tp->t_force = 1;

 (void) tcp_output(tp);

tp->t_force = 0;

 break;

        其也在重传移位计数器>TCP_MAXRXTSHIFT后drop连接。         下图为持续定时器取值时间表(假设连接的重传时限为1.5s):

        图中可以看出坚持定时器也采用了指数退避策略。

3.5 FIN_WAIT_2定时器

        TCP的TCP2_2MSL定时计数器实现了两种定时器:FIN_WAIT_2定时器和2MSL定时器。         FIN_WAIT_2定时器。当tcp_input从FIN_WAIT_1状态变迁为FIN_WAIT_2状态(调用了close,而不是shutdown),FIN_WAIT_2定时器设定为10分钟(tcp_maxidle)。这样可以防止连接永远停留在FIN_WAIT_2状态。         代码如下所示:

/*

* 2 MSL timeout in shutdown went off. If we're closed but

* still waiting for peer to close and connection has been idle

* too long, or if 2MSL time is up from TIME_WAIT, delete connection

* control block. Otherwise, check again in a bit.

*/

 case TCPT_2MSL:

 if (tp->t_state != TCPS_TIME_WAIT &&

tp->t_idle <= tcp_maxidle)

tp->t_timer[TCPT_2MSL] = tcp_keepintvl;

 else

tp = tcp_close(tp);

 break;

3.6 2MSL定时器

        TCP的TCP2_2MSL定时计数器同时也实现了2MSL定时器,代码如上一节所示。MSL是指的报文段最大生存时间,设定一个2MSL的等待状态是为了不让网络中幸存的包(可能缓存在路由器中、经过多个路由器导致时间滞后的)重新发送给已经关闭的连接。

4. 总结

        TCP作为一个通用的网络协议,其作者们为了可靠性做出了巨大的努力,从而导致TCP内部存在各种机制,异常复杂,本文通过对TCP窗口和定时器所采用的各种算法进行了介绍,从而让大家能够进一步理解TCP协议。

## 原文链接   

https://my.oschina.net/alchemystar/blog/833981    

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏jeremy的技术点滴

TCP细节分析

33660
来自专栏java初学

TCP/IP三次握手与四次挥手

30170
来自专栏用户画像

1.2.3.2 TCP/IP模型

TCP/IP模型,从低到高依次为:网络接口层(对应OSI参考模型中的物理层和数据链路层)、网际层、传输层和应用层(对应OSI参考模型中的会话层、表示层和应用层)...

7700
来自专栏吴老师移动开发

TCP/IP协议

18450
来自专栏小筱月

三次握手和四次挥手

OSI参考模型中的网络层,在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。(TCP在运输层,IP在网络层)

11510
来自专栏小筱月

TCP、UDP 的区别,三次握手、四次挥手

|TCP 面向连接(如打电话要先拨号建立连接)|UDP 是无连接的,即发送数据之前不需要建立连接|

41050
来自专栏mathor

计算机网络基础知识总结

 为了使不同计算机厂家生产的计算机能相互通信,在更大范围内建立计算机网络,国际标准化组织(ISO)在1978年提出了“开放系统互联参考模型”,即著名的OSI/R...

1K20
来自专栏土豆专栏

计算机网络基础知识整理--数据链路层

小编最近在复习计算机网络基础,整理出来一些我认为比较重要的知识。希望能帮到大家哈,后续会更新~

826120
来自专栏北京马哥教育

TCP三次握手与四次分手傻傻分不清?看大神图解五分钟讲明白

引言 TCP三次握手和四次挥手不管是在开发还是面试中都是一个非常重要的知识点,它是我们优化web程序性能的基础。但是大部分教材都对这部分解释的比较抽象,本文我们...

37770
来自专栏Android点滴积累

HandlerThread 创建一个异步的后台线程

使用HandlerThread几大优点: 1、制作一个后台异步线程,需要的时候就可以丢一个任务给它,使用比较灵活; 2、Android系统提供的,使用简单方便,...

24760

扫码关注云+社区

领取腾讯云代金券