有时netstat会显示一个看似卡住的套接字。远程应用程序已被终止,有时甚至OpenVOS应用程序也已终止,但netstat仍显示该套接字。本文将解释这种现象的原因及应对措施。
TCP状态简述
若在谷歌搜索“TCP状态图”,你会发现大量相关图片,有些几乎无法辨认,有些则清晰易读。维基媒体提供了一张非常精美的彩色编码图(http://commons.wikimedia.org/wiki/File:TCP_state_diagram.png)。 TCP RFC 793(http://www.rfc-editor.org/rfc/rfc793.txt)提供了ASCII艺术图示,并详细阐释了各状态的含义。
套接字在等待本地应用程序或远程主机执行操作时可能陷入阻塞状态。这种情况主要发生在三个状态中:FIN_WAIT_2状态下,套接字等待远程主机关闭连接;CLOSE_WAIT状态下,它等待本地应用程序关闭套接字;而在ESTABLISHED状态下,它等待远程主机打开发送窗口,或等待本地应用程序发送数据。 在CLOSE_WAIT状态下,它等待本地应用程序关闭套接字;而在ESTABLISHED状态下,它等待远程主机打开发送窗口,或等待本地应用程序发送数据。若本地TCP堆栈已发送数据且正在等待远程主机确认,则不会卡住——它最终会超时,向本地应用程序发送错误信号并关闭套接字。
FIN_WAIT_2 状态
这可能是CAC接到的最常见的套接字卡死案例。本地应用程序已关闭套接字,甚至可能已终止运行。套接字陷入这种状态的典型原因是远程应用程序已挂起且未读取其套接字。
将STCP参数finwait2设置为某个N > 0值后,当套接字处于FIN_WAIT_2状态达到N秒时将关闭该套接字。自14.7.2bg、14.7.tl1、 15.2.1aa、15.2.tel.af、15.3.0bd、15.3.tel.ag、16.2.1al、17.0.0ai及17.1版本中,该参数默认值为1200秒;此前版本默认值为0(若需使套接字超时,需手动设置)。 可通过list_stcp_params分析系统请求查看当前值,使用set_stcp_param分析系统请求修改该值。相关请求的文档详见《OpenVOS系统分析(R073)》手册,可访问stratus获取。
CLOSE_WAIT 状态
这是第二常见的卡死套接字状态。处于CLOSE_WAIT状态的套接字正在等待本地应用程序关闭套接字。套接字滞留此状态的典型原因是应用程序不再读取该套接字。关闭套接字最简便的方式是终止本地应用程序。
若无法终止本地应用程序,唯一可行的方法是构造一个设置了RST(重置)标志的数据包。这需要您了解套接字使用的序列号(可通过dump_onetcb analyze_system请求获取),并在本地子网的另一台主机上具备能够构建并发送自定义IP数据包的工具。此类工具在Windows和Linux系统上均可使用。
已建立的状态
由于netstat命令显示的套接字大多处于ESTABLISHED状态,如何判断套接字是否卡死?当收到远程主机崩溃的报告,或本地与远程主机间的网络连接中断超过10分钟,且本地应用程序仍在等待远程发送数据时,即可基本确定套接字已卡死。 此时netstat报告的发送队列值(本地IP地址左侧的数值)将为0。反之,若发送队列值大于0且持续保持该状态,则可能是远程主机报告了零窗口的情况。
在第一种情况下,除非启用保持活动功能,否则套接字将保持在已建立状态,直至本地应用程序终止。若启用保持活动功能,则在保持活动计时器超时后,STCP将发送保持活动探测请求。若探测请求未获响应,系统将进行重传,但在数分钟内多次重传后,连接将被终止。 默认情况下接口启用了保持活动功能,但套接字默认未启用。要为套接字启用保持活动,应用程序必须调用setsockopt函数。详情请参阅《OpenVOS STREAMS TCP/IP编程指南(R420)》,该手册也可在stratus获取。 默认保持活动时间为2小时,这意味着首次探测将在收到远程主机最后一个TCP分段后2小时触发,因此需保持耐心。若需调整,可通过analyze_system中的set_stcp_parameter请求修改保持活动时长、探测间隔及探测次数。但不建议在未进行详细分析的情况下更改这些参数。
如果套接字未设置保持活动状态,则唯一简单的选项是终止拥有该套接字的应用程序。如果这不可行,则可通过发送设置了RST标志的分段来关闭套接字。
要确认第二种情况,请检查由dump_onetcb analyze_system请求显示的sndws值。0值表示窗口已关闭。您还可以运行packet_monitor来追踪连接,并在来自远程主机的分段中检查TCP头中的窗口值。值为“n.a.”表示0。
我想强调的是,这种情况可能是可恢复的。 应用程序有时会出现延迟,此时TCP协议栈会关闭通信窗口;当应用程序恢复正常后,协议栈会重新打开窗口。不过在大多数情况下,若应用程序在数分钟内仍未恢复,通常可以安全地认为其无法恢复。例外情况可能是打印机缺纸等状态。处于此状态的套接字即使创建它的VOS应用程序终止,仍可能保持该状态。
这些套接字可通过将 tcp_zerowin_abort_interval$ 设置为某个 N > 0 的值来清理。在收到下一个窗口值为零的 TCP 数据段后 N 秒,套接字将被清理。系统每 100 秒发送一次窗口探测请求以确认远程主机的接收窗口仍处于关闭状态,因此最迟会在 100 秒内收到响应。 tcp_zerowin_abort_interval$ 的默认值为零,除非需要清理套接字,否则建议保持该值为0。若需清理,建议设置为较小值(如10秒),清理完成后立即重置为0。此举可降低误清除可恢复套接字的风险。
要设置此值,必须在analyze_system中使用set_longword请求,请注意N将以十六进制形式表示。例如,若要将其设为10,请求应为:
set_longword tcp_zerowin_abort_interval$ a
