Coverage for qreward / utils / socket_keepalive.py: 100.00%
34 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-23 19:32 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-23 19:32 +0000
1import socket
2import sys
3from typing import List
5from requests.adapters import HTTPAdapter
7from qreward.types import SOCKET_OPTION
10def aiohttp_keepalive_socket_factory(
11 addr_info,
12 keepalive_secs: int = 60,
13 keepalive_interval: int = 30,
14 keepalive_cnt: int = 3,
15) -> socket.socket:
16 """aiohttp 保持 keepalive 连接的 socket 工厂函数
18 Args:
19 addr_info (tuple): socket 地址信息
20 keepalive_secs (int, optional): 保持 keepalive 连接的时间, 默认 60 秒
21 keepalive_interval (int, optional): 保持 keepalive 连接的间隔, 默认 30 秒
22 keepalive_cnt (int, optional): 保持 keepalive 探测的次数, 默认 3 次
24 Returns:
25 socket: socket 对象
26 """
28 family, type_, proto, _, _ = addr_info
30 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
31 sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
33 if sys.platform.startswith("linux"):
34 # Linux
35 sock.setsockopt(
36 socket.IPPROTO_TCP,
37 socket.TCP_KEEPIDLE,
38 keepalive_secs,
39 )
40 elif sys.platform.startswith("darwin"):
41 # Darwin
42 sock.setsockopt(
43 socket.IPPROTO_TCP,
44 socket.TCP_KEEPALIVE,
45 keepalive_secs,
46 )
48 sock.setsockopt(
49 socket.IPPROTO_TCP,
50 socket.TCP_KEEPINTVL,
51 keepalive_interval,
52 )
53 sock.setsockopt(
54 socket.IPPROTO_TCP,
55 socket.TCP_KEEPCNT,
56 keepalive_cnt,
57 )
58 return sock
61def httpx_keepalive_socket(
62 keepalive_secs: int = 60,
63 keepalive_interval: int = 30,
64 keepalive_cnt: int = 3,
65) -> List[SOCKET_OPTION]:
66 """
67 httpx 保持 keepalive 连接的 socket 选项
69 :param keepalive_secs: 保持 keepalive 连接的时间, 默认 60 秒
70 :param keepalive_interval: 保持 keepalive 连接的间隔, 默认 30 秒
71 :param keepalive_cnt: 保持 keepalive 探测的次数, 默认 3 次
72 :return: socket 选项列表
73 """
75 socket_options = [
76 (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), # 启用keepalive
77 ]
79 if sys.platform.startswith("linux"):
80 socket_options.append(
81 (
82 socket.IPPROTO_TCP,
83 socket.TCP_KEEPIDLE,
84 keepalive_secs,
85 )
86 )
87 elif sys.platform.startswith("darwin"):
88 socket_options.append(
89 (
90 socket.IPPROTO_TCP,
91 socket.TCP_KEEPALIVE,
92 keepalive_secs,
93 )
94 )
96 socket_options.append(
97 (
98 socket.IPPROTO_TCP,
99 socket.TCP_KEEPINTVL,
100 keepalive_interval,
101 )
102 )
103 socket_options.append(
104 (
105 socket.IPPROTO_TCP,
106 socket.TCP_KEEPCNT,
107 keepalive_cnt,
108 )
109 )
110 return socket_options
113class RequestsTCPKeepAliveAdapter(HTTPAdapter):
114 """自定义适配器:注入keepalive socket选项"""
116 def __init__(self, *args, **kwargs):
117 self._default = httpx_keepalive_socket()
118 self.socket_options = kwargs.pop("socket_options", self._default)
119 super().__init__(*args, **kwargs)
121 def init_poolmanager(
122 self,
123 connections,
124 maxsize,
125 block=False,
126 **pool_kwargs,
127 ):
128 if self.socket_options is not None:
129 pool_kwargs["socket_options"] = self.socket_options
130 super().init_poolmanager(connections, maxsize, block, **pool_kwargs)