如何使用Python脚本更改TCP Keepalive计时器?

40

在我的Python脚本中,我使用了以下命令来激活TCP Keepalive:

x = s.setsockopt( socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
我的目标是,如果在5分钟内没有传输(*),则关闭套接字连接。我正在Windows上工作,我的Python脚本仅接收数据而不向客户端程序发送任何数据。
我知道,默认情况下,如果2个小时没有传输,我才可以使用try和except来关闭连接。我知道,对于Windows,我可以手动减少此等待时间,方法是进入注册表。但是有没有一种方法可以从我的脚本中修改它呢?
(*) 这里的“无传输”意味着“网络上有某个东西悄悄地吃掉了数据包”,而不是“我没有尝试发送任何内容”。

澄清了“无传输”是什么意思。 - Dima Tisnek
为什么不设置一个读取超时时间呢? - user207421
3个回答

73

您可以使用setsockopt()函数设置已打开套接字上的TCP keepalive计时器。

import socket

def set_keepalive_linux(sock, after_idle_sec=1, interval_sec=3, max_fails=5):
    """Set TCP keepalive on an open socket.

    It activates after 1 second (after_idle_sec) of idleness,
    then sends a keepalive ping once every 3 seconds (interval_sec),
    and closes the connection after 5 failed ping (max_fails), or 15 seconds
    """
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, after_idle_sec)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, interval_sec)
    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, max_fails)

def set_keepalive_osx(sock, after_idle_sec=1, interval_sec=3, max_fails=5):
    """Set TCP keepalive on an open socket.

    sends a keepalive ping once every 3 seconds (interval_sec)
    """
    # scraped from /usr/include, not exported by python's socket module
    TCP_KEEPALIVE = 0x10
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
    sock.setsockopt(socket.IPPROTO_TCP, TCP_KEEPALIVE, interval_sec)

如需在 Windows 上使用等效选项,请参考 MSDN

查看Python 源代码,似乎需要使用 sock.setsockopt 在 Windows 中设置SO_KEEPALIVE,并且[可选?]使用 sock.ioctl 设置SIO_KEEPALIVE_VALS,与 Unix 类似。


2
请注意,此处使用的TCP_*常量是特定于Linux的。例如,它们在OS/X上不可用。 - RobM
1
osx的man tcp包含一个选项TCP_KEEPALIVE,它接受探测之间的秒数,相当于linux中的TCP_KEEPINTVL。该选项在Python 2.7或3.3中未导出,但我认为可以使用正确的整数值0x10作为键。 - Dima Tisnek
1
@DimaTisnek TCP_KEEPINTVL 看起来是等价的,但你是怎么得到值 0x10 的? - Alex Choi
达尔文tcp.h:https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/bsd/netinet/tcp.h - Dima Tisnek
有关Solaris的任何想法 - '_socketobject'对象没有属性'IPPROTO_TCP',也没有SOL_SOCKET - Kingsley

15

对于Windows平台,在Python中:

这将启用套接字保持活动功能,其中保持活动时间为10秒,保持活动间隔为3秒。

sock.ioctl(socket.SIO_KEEPALIVE_VALS, (1, 10000, 3000))

0
我已经将上述答案结合起来,为Linux、Darwin和Windows制作了一个单功能版本。

https://pypi.org/project/keepalive-socket/

pip install keepalive-socket

import socket, keepalive

# keepalive.set(socket, after_idle_sec=60, interval_sec=60, max_fails=5)

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
keepalive.set(client_socket)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接