有时Netstat 命令行工具显示的套接字(socket)似乎卡住了。当远程应用已终止,有时甚至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状态下,它在等待远程主机打开它的发送窗口,或者等待本地应用程序发送一些东西。如果本地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 analyze_system请求查看当前值,你可以用set_stcp_param analyze_system请求更改该值。参见OpenVOS系统分析(R073)手册,可在http://stratadoc。stratus.com,了解这些请求的文档。
CLOSE_WAIT状态
这是下一个最常见的卡住的套接字状态。处于CLOSE_WAIT状态的套接字正在等待本地应用程序关闭套接字。套接字保持这种状态的典型原因是应用程序不再读取该套接字。关闭套接字最简单的方法是终止本地应用程序。
如果终止本地应用程序不是一个选项,你唯一能做的就是制作一个设置了RST(复位)标志的数据包。这需要你知道套接字使用的序列号(可以使用dump_onetcb analyze_system请求),并且在本地子网的另一台主机上有一个实用程序,可以构建和发送自定义的IP包。这些实用程序适用于Windows和Linux系统。
ESTABLISHED state
既然大多数时候netstat显示的套接字都是ESTABLISHED状态,那么如何判断套接字什么时候卡住呢?如果你有报告说远程主机崩溃了,或者本地和远程主机之间的网络故障超过10分钟,而本地应用程序正在等待远程发送东西,你可以很肯定的说套接字被卡住了。在这种情况下,netstat报告的发送队列值(本地IP地址左边的数字)将是0,另一方面,如果发送队列值大于0并保持在那里,你可能会出现远程主机广告零窗口的情况。
在第一种情况下,除非keep-alive被打开,否则套接字将保持在ESTABLISHED状态,直到本地应用程序被终止。如果开启了keep-alive,那么在keep-alive计时器到期后,STCP将发送一个keep-alive探针。如果探针无人应答,它将被重新发送,但在几分钟和几次重新发送后,连接将被终止。默认情况下,接口已经设置了keep-alive,但默认情况下,套接字没有设置keep-alive。要在一个套接字上设置keep-alive,应用程序必须使用setockopt函数调用。详情请参见OpenVOS STREAMS TCP/IP Programming (R420)手册,也可以在http://stratadoc.stratus.com上找到。默认的keep-alive时间是2小时,也就是说,第一个keep-alive探针是在接收到远程主机的最后一个TCP段后2小时传送的,所以你一定要有耐心。对于那些没有耐心的人,你可以在analyze_system中通过set_stcp_parameter请求来调整keep-alive时间,以及探针之间的时间和探针的数量。在没有详细分析之前,我不建议改变这些参数。
如果套接字没有设置keep-alive,唯一简单的选择就是终止拥有套接字的应用程序。如果这不是一个选择,可以通过发送一个设置了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,我建议它保持在0,除非你需要清理一个socket。这时我建议把它设置为一个小值,比如10秒,一旦套接字被清理干净,就把它重置为0,我认为这样可以降低清理可以恢复的套接字的风险。
要设置这个值,你必须使用analyze_system中的set_longword请求,所以记住N是十六进制。例如,如果要将其设置为10,则请求如下。
set_longword tcp_zerowin_abort_interval$ a。