FireFox、Chrome、Edge、Safariなどのすべてのブラウザは、確立されたTCP接続が確立されたままであることを確認するために、頻繁にTCPキープアライブを使用し、接続が切断された場合に再接続します。確立されたTCP接続には、キープアライブがどのように機能するかを決定する3つの構成可能なプロパティがあります。Linuxでは次のようになります。
- tcp_keepalive_time(デフォルトは7200秒)
- tcp_keepalive_probes(デフォルトは9)
- tcp_keepalive_intvl(デフォルトは75秒)
Pythonリクエストは、ソケットでTCPキープアライブを有効にすることはありません(Linuxでは、デフォルトでTCPキープアライブはソケットで有効になっていないため、アプリケーションで有効にする必要があります)。Pythonリクエストは、各OSのデフォルトのソケットオプションを使用するため、HTTP 1.1持続的接続の場合、接続がアイドル状態のままである場合に確立された接続がドロップされるかどうかはわかりません。接続が切断された場合、次のソケット書き込みがいつ発生するかしかわかりません。デフォルトよりも低いtcp_keepalive_timeを使用すると、ドロップされたアイドル接続の診断に役立ちます。tcp_keepalive_intvlは、2つのキープアライブ間の間隔です。
以下のコードでは、ユーザー定義のHTTPAdapterを使用して、基になるurllib3を介してソケットオプションを設定するリクエスト推奨の方法を使用しています。(socket.SOL_SOCKET、socket.SO_KEEPALIVE、1)はキープアライブを有効にし、他の2つはtcp_keepalive_timeとtcp_keepalive_intvlを10秒に設定しています。
TCPキープアライブはプラットフォームに依存することを忘れないでください。このコードは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)