《TCP/IP协议卷1》 TCP的坚持和保活定时器
第22章 TCP的坚持定时器
引言
- TCP通过接收方指明的窗口大小进行流量控制。窗口为0时,发送方停止发送数据,直到窗口非0 。
- ACK传输不可靠,TCP不确认不含数据的ACK报文段。若确认丢失,连接可能因双方等待陷入死锁。
- 发送方使用坚持定时器周期性向接收方查询窗口是否增大,发出的报文段称窗口探查,本章讨论窗口探查、坚持定时器及糊涂窗口综合症。
一个例子
- 通过启动接收进程并设置sock程序休眠选项 -P让服务器在接收连接和读数据间休眠,观察坚持定时器。
- 客户向服务器5555端口写1024字节,报文中1 - 13段是正常数据传输,服务器通告窗口从4096字节变为0,客户设置坚持定时器。
- 窗口探查间隔如4.949秒、4.996秒等,后续约为6、12、24、48和60秒,源于500ms定时器超时,超时时间按超时值乘指数退避计算,范围在5 - 60秒。
- 窗口探查含序号9217的一个字节数据,返回窗口为0的ACK不确认该字节,而是确认9216字节。
- 坚持状态下TCP每隔60秒发窗口探查,持续到窗口打开或应用进程终止连接。这部分内容围绕“糊涂窗口综合症(SWS,Silly Window Syndrome )”展开。
基于窗口的流量控制方案(如TCP所用)会引发“糊涂窗口综合症”,出现该情况时,连接中只有少量数据交换,而非满长度报文段传输。
在TCP连接两端,接收方通告小窗口,或发送方在等待大窗口时先发送少量数据,都可能触发该现象。
避免措施
接收方:通常不通告小窗口,除非增大窗口(到MSS或使接收缓存空间达一半) 。
发送方:满足以下条件之一才发送数据:
- 能发送满长度报文段。
- 可发送至少为接收方通告窗口大小一半的报文段,用于应对总通告小窗口的主机。
- 能发送数据且不期望接收ACK(无未确认数据或连接不能用Nagle算法),避免在有未确认数据且不能用Nagle算法时发送小报文段。
通过在发送主机 sun
运行sock -i -n6 bsdi 7777
向网络写6个1024字节数据,在接收主机 bsdi
运行sock -i -s -p4 -p2 -z256 7777
并设置不同读数据前暂停时间(首次4秒,之后每次2秒) ,结合图22 - 2(显示接收方避免糊涂窗口综合症时间系列)和图22 - 3(接收方避免糊涂窗口综合症事件序列) ,展示实际避免该症状的过程:
- 接收方初始暂停使接收缓存填满,让发送方停止发送。后续接收方从网络接收少量数据,采取措施避免综合症。
- 发送方在坚持定时器触发时,按规则发送数据并被确认,接收方通告窗口变化,发送方根据窗口情况发送数据。
- 发送应用进程执行完写操作后关闭连接,经历
ESTABLISHED
到FIN_WAIT_1
再到FIN_WAIT_2
状态转变,接收应用进程按设置频率读取数据,接收缓存空间变化影响窗口通告,最终连接结束 。
第23章 TCP的保活定时器
23.1 引言
- 空闲TCP连接特性:许多TCP/IP初学者会惊讶发现,在无任何数据流通过的空闲TCP连接中,连接双方若都不发送数据,两个TCP模块间不会交换任何信息。即便在其他网络协议中能检测轮询,此连接也可长时间保持,像主机未重启,连接就持续存在。
- 应用进程检测需求:这意味着应用进程(客户或服务器进程)缺乏应用级定时器检测非活动状态,可能导致进程终止活动。如BGP每隔30秒向对端发送应用探查,是独立于TCP的保活定时器之外的机制。
- 服务器需求与保活机制争议:很多时候服务器希望知晓客户主机是否崩溃、关机或重启,保活定时器可满足此需求。但保活并非TCP规范部分,Host Requirements RFC给出不使用保活定时器的理由:(1)可能在短暂暂错情况下致正常连接释放;(2)存在计费问题;(3)按需分组计费时会多花钱。不过,实际中仍有很多实现提供了保活定时器,且该功能是否应在TCP中提供存在争论 。
- 保活机制问题:网络出现临时故障时,保活选项可能导致正常连接被误判终止。比如中间路由器崩溃重启发送保活探查,TCP可能误认客户主机崩溃。
- 保活功能应用场景:保活功能主要供服务器应用程序判断客户主机状态,像Rlogin和Telnet服务器默认使用该选项。以个人计算机用TCP/IP连接Telnet主机为例,若连接结束时仅关闭电源未注销,会留下半开放连接。服务器若收到来自客户端的数据会复位,若客户端消失,服务器会一直等待,保活功能就是尝试检测这类半开放连接。
23.2 描述
- 保活功能设置主体:通常是服务器设置保活选项,不过客户也可使用,特殊情况下双方都可能设置。如在第29章涉及NFS使用TCP时,客户和服务器都设置了该选项,但第26章提到Telnet和Rlogin时,只有服务器设置。
- 保活探查机制:若给定连接两小时内无动作,服务器向客户发送探查报文段。客户主机存在以下4种状态及对应服务器处理方式:
-
- 主机正常且可达:客户TCP正常响应,服务器知晓对方正常工作,两小时后重置保活定时器,若两小时内有通信则提前复位定时器。
- 主机崩溃、关闭或重启且无响应:服务器收不到响应,75秒后超时,共发送10个探查,间隔75秒,若都无响应,认定客户主机关闭并终止连接。
- 主机崩溃后重启:服务器会收到保活探查响应,连接恢复正常。
- 主机正常但不可达:与状态2类似,TCP无法区分,服务器发现无响应后按状态2处理。
- 服务器对不同状态的处理:在第1种情况中,TCP层负责一切,过程对应用程序透明;第2、3、4种情况发生时,服务器应用程序会收到TCP的差错报告(读操作请求后等待客户数据,保活功能返回差错,读操作返回值给服务器)。第2种情况返回“连接超时”类差错,第3种为“连接被对方复位” ,第4种可根据有无相关ICMP差错返回其他差错。
- 保活空闲时间争议与设置:关于保活选项中两小时空闲时间能否改变存在讨论,人们常希望缩短至分钟量级。实际中该值在系统层面可变,会影响所有使用保活功能的用户。Host Requirements RFC规定实现可提供保活功能,但需应用程序指明,且保活间隔可配置,默认值不小于两小时。
23.3 保活举例
23.3.1 另一端崩溃
- 模拟步骤及预期:在主机bsdi(运行sock程序)和主机svr4(标准回显服务器)间建立连接,客户用 -K 选项启用保活功能。验证连接可传输数据后,拔掉服务器网线模拟其崩溃。预期服务器发送10个间隔75秒的保活探查。
- 客户端交互输出分析:客户发送“Hello, world”得到回显。两小时后发送保活分组,第4行是首个保活探查。部分旧的基于4.2BSD的实现对不含数据的保活探查无响应,因数据无用会被丢弃;有的系统在前半部分发4.3BSD格式报文段(不含数据),无响应则后半部分切换为4.2BSD格式。拔掉网线后服务器无ARP请求响应,客户每75秒发一个探查,共10次,最终应用程序收到“连接超时”差错 。
23.3.2 另一端崩溃并重新启动
- 模拟及预期:环境与上例相似,验证连接有效后断开服务器网络,重启后再连入,预期服务器发送复位保活探查。
- 客户端交互输出分析:客户发送数据,两小时后发第1个保活探查,收到服务器复位,客户应用进程打印“连接被对端复位” 。
23.3.3 另一端不可达
- 模拟及预期:从主机slip经拨号SLIP链路与主机vangogh.cs.berkeley.edu建立连接,然后断开链路模拟不可达情况。
- 客户端交互输出分析:客户发送数据验证连接有效,两小时后发保活探查,收到来自sun和netb之间SLIP连接断开的ICMP网络不可达差错(对发送主机slip的TCP是软差错,不终止连接)。发送主机共发送9个保活探查,间隔75秒,最终应用进程收到“没有到达主机的路由”差错 。
23.3.4 小结
保活功能存在争议,专家对其应归属运输层还是由应用层处理看法不一。连接空闲两小时后,会发探查分组,可能出现对端仍正常运行、已崩溃、崩溃后重启、当前无法到达4种情况,通过实例展示了后三种情况的不同差错返回。若两端都无定时器,客户无法知晓对端崩溃或重启,使用保活功能时需关注此局限。