12.4 SO_KEEPALIVE的相关讨论 https://scz.617.cn/network/200604201416.txt D: microsoft SOCK_STREAM型套接字支持SO_KEEPALIVE选项,SOCK_DGRAM型套接字不支持。缺省没 有启用保活机制。缺省超时时限是2小时,与之对应的注册表项如下: 95: -------------------------------------------------------------------------- REGEDIT4 [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\Parameters] "KeepAliveTime"=dword:006ddd00 "KeepAliveInterval"=dword:000003e8 "MaxDataRetries"="5" -------------------------------------------------------------------------- KeepAliveTime缺省7200000毫秒(ms),也就是两小时。KeepAliveInterval缺省1000 毫秒,也就是1秒。MaxDataRetries缺省5次。 98: -------------------------------------------------------------------------- REGEDIT4 [HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\Parameters] "KeepAliveTime"="7200000" "KeepAliveInterval"="1000" "MaxDataRetries"="5" -------------------------------------------------------------------------- 98上这三项都是REG_SZ型,与其它系统不同。 NT 4: -------------------------------------------------------------------------- REGEDIT4 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] "KeepAliveTime"=dword:006ddd00 "KeepAliveInterval"=dword:000003e8 "MaxDataRetries"="5" -------------------------------------------------------------------------- 2000/XP/2003: -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters] "KeepAliveTime"=dword:006ddd00 "KeepAliveInterval"=dword:000003e8 "MaxDataRetries"="5" -------------------------------------------------------------------------- 这些注册表项影响范围是整个系统。 从2000开始引入一个新的I/O控制命令SIO_KEEPALIVE_VALS,可通过WSAIoctl()针对 单个套接字设置是否启用保活机制、KeepAliveTime、KeepAliveInterval。 -------------------------------------------------------------------------- /* * Argument structure for SIO_KEEPALIVE_VALS */ struct tcp_keepalive { u_long onoff; u_long keepalivetime; u_long keepaliveinterval; }; -------------------------------------------------------------------------- D: scz 2002-05-13 10:40 下面是*nix系统上的相关讨论。 可以使用SO_KEEPALIVE套接口选项保持TCP连接,缺省是2小时。参看UNP 7.5小节。 -------------------------------------------------------------------------- int on = 1; if ( setsockopt ( s, SOL_SOCKET, SO_KEEPALIVE, &option, sizeof( on ) ) < 0 ) { ... ... } -------------------------------------------------------------------------- <> 23.3.1小节有对此选项的进一步讨论。 这个选项通常是基于整个内核的,而不是基于单个套接字的,所以一切对它超时时限 的改变将影响本机所有设置了该选项的套接字。该选项是个乒乓开关,不能在设置该 选项时直接指定超时时限。一般各系统提供了命令行设置手段: -------------------------------------------------------------------------- x86/Linux kernel 2.4.7-10 /sbin/sysctl net.ipv4.tcp_keepalive_time 或 /proc/sys/net/ipv4/tcp_keepalive_time x86/FreeBSD 4.5-RELEASE sysctl net.inet.tcp.keepidle SPARC/Solaris 8 ndd /dev/tcp tcp_keepalive_interval -------------------------------------------------------------------------- UNP 7.9小节介始了TCP_KEEPALIVE选项,但它没有被广泛实现。这是Stevens十年前 说的,现在的Linux、FreeBSD和Solaris是否支持,尚未测试。我在Solaris上找到了 一个宏定义,奇怪的是,Linux和FreeBSD反是没有: find /usr/include -type f | xargs grep TCP_KEEPALIVE | grep "#define" /usr/include/netinet/tcp.h #define TCP_KEEPALIVE 0x8 /* set keepalive timer */ Linux直接操作/proc/sys/net/ipv4/tcp_keepalive_time设置超时时限。FreeBSD用 sysctl()设置。 此外UNP 21.5小节讨论了另外一些保持TCP连接的C/S模式心跳函数,但那是用户态的 实现,非TCP/IP协议栈的实现。 UNP 5.12讨论了服务进程终止时,客户端如何发觉。UNP 6.7小节给出了一个客户端 实现。更多时候关心的是,客户端不发送携带有效负载的TCP报文,如何发觉一个TCP 连接已经被服务端关闭、半关闭。 参看UNP 6.11小节和图7.5。UNP 6.3讨论了select()函数,UNP 6.10讨论了poll()函 数。 如果用select(),可以监视读满足时进行read(),如果返回值小于等于零,则认为需 要显式关闭套接字重新创建TCP连接了。对于poll()情况类似,只是初始化poll()调 用时,最好指定POLLRDNORM,而不是POLLIN。事实上这里简单调用select()或poll() 监视读满足即可,不必read(),因为客户端不发送数据,Apache是不会主动发送数据 过来的,正常时,被监视句柄应该无情况,除非FIN包或RST包到达。 有一种情况,Apache进程所在主机崩溃,服务端TCP/IP协议栈没机会发送FIN包,客 户端无法意识到发生过什么,陷入无限等待中。应该给poll()带上超时设置,超时后 显式关闭套接字重新创建TCP连接。