所有浏览器(如 FireFox、Chrome、Edge 或 Safari)都将使用非常频繁的 TCP keepalives 来确保已建立的 TCP 连接保持建立,如果连接断开,它们会重新连接。在已建立的 TCP 连接上,有三个可配置的属性确定 keepalive 的工作方式。在 Linux 上,它们是:
- tcp_keepalive_time(默认 7200 秒)
- tcp_keepalive_probes(默认 9)
- tcp_keepalive_intvl(默认 75 秒)
Python 请求永远不会在套接字上启用 TCP keepalive(在 Linux 上,默认情况下 TCP keepalive 未在套接字上启用,应用程序必须启用它)。Python 请求使用每个操作系统上的默认套接字选项,因此对于 HTTP 1.1 持久连接,我们不知道如果连接保持空闲,是否会丢弃已建立的连接。在断开的连接上,我们只会知道下一次套接字写入发生的时间。使用低于默认值的 tcp_keepalive_time 有助于诊断断开的空闲连接。tcp_keepalive_intvl 是两个 keepalive 之间的间隔。
在下面的代码中,我们使用请求推荐的方式使用用户定义的 HTTPAdapter 通过底层 urllib3 设置套接字选项。(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) 是启用keepalives,另外两个将tcp_keepalive_time和tcp_keepalive_intvl设置为10秒。
记住 TCP keepalive 依赖于平台。此代码仅适用于 Linux。
import requests, socket
from requests.adapters import HTTPAdapter
class HTTPAdapterWithSocketOptions(HTTPAdapter):
def __init__(self, *args, **kwargs):
self.socket_options = kwargs.pop("socket_options", None)
super(HTTPAdapterWithSocketOptions, self).__init__(*args, **kwargs)
def init_poolmanager(self, *args, **kwargs):
if self.socket_options is not None:
kwargs["socket_options"] = self.socket_options
super(HTTPAdapterWithSocketOptions, self).init_poolmanager(*args, **kwargs)
KEEPALIVE_INTERVAL = 10
adapter = HTTPAdapterWithSocketOptions(socket_options=[(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, KEEPALIVE_INTERVAL), (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, KEEPALIVE_INTERVAL)])
s = requests.Session()
s.mount("http://", adapter)
s.mount("https://", adapter)