使用aiohttp通过SSH代理隧道异步请求时遇‘Server Disconnected’错误
解决aiohttp异步请求通过SSH SOCKS代理时出现Server disconnected的问题
问题场景
通过以下命令建立SSH动态SOCKS5代理隧道:
sshpass -p "<my_pass>" ssh -D 8090 my_user@my_server.com
同步HTTP请求(如requests结合socks代理)可正常工作,但使用aiohttp发起异步请求时,频繁触发ServerDisconnectedError,无代理或同步请求时无此问题。
解决方案
1. 优化SSH隧道的存活配置
SSH服务器默认会断开长时间空闲的连接,异步请求的连接模式更容易触发该机制。修改SSH命令,添加保活参数:
sshpass -p "<my_pass>" ssh -D 8090 -o ServerAliveInterval=30 -o ServerAliveCountMax=5 my_user@my_server.com
ServerAliveInterval=30:每30秒向SSH服务器发送一次存活检测包ServerAliveCountMax=5:连续5次检测无响应才主动断开连接
2. 复用aiohttp ClientSession
原代码中每次请求都创建新的ClientSession,会频繁与SOCKS代理建立新连接,增加断开风险。改为复用Session实例:
async def _resilient_request( self, url: str, headers: Dict[str, str] ) -> Dict[str, Any]: proxy = "socks5h://localhost:8090" # 新增连接超时设置,避免连接代理时长时间等待 timeout = aiohttp.ClientTimeout(total=30, connect=10) # 把ClientSession创建移到循环外,复用连接池 async with aiohttp.ClientSession( timeout=timeout, json_serialize=ujson.dumps, ) as session: for attempt in range(8): try: async with session.get(url, headers=headers, ssl=False, proxy=proxy) as resp: resp.raise_for_status() data = await resp.json() return data except ( aiohttp.ClientError, aiohttp.ClientResponseError, asyncio.TimeoutError, aiohttp.ServerDisconnectedError, aiohttp.ClientConnectorError, RuntimeError, ) as err: if attempt < 3: await asyncio.sleep(attempt + 1) print(f"Resilient request failed. Retrying attempt {attempt + 1}") print(f"Error: {err}") continue else: raise err
3. 使用专用SOCKS代理库提升兼容性
如果原生aiohttp的SOCKS支持存在兼容性问题,改用aiohttp-socks库处理代理:
- 安装依赖:
pip install aiohttp-socks
- 修改代码中的Session配置:
from aiohttp_socks import ProxyConnector async def _resilient_request( self, url: str, headers: Dict[str, str] ) -> Dict[str, Any]: # 用专用连接器配置SOCKS代理 connector = ProxyConnector.from_url("socks5h://localhost:8090") timeout = aiohttp.ClientTimeout(total=30, connect=10) async with aiohttp.ClientSession( connector=connector, timeout=timeout, json_serialize=ujson.dumps, ) as session: for attempt in range(8): try: # 无需再单独传proxy参数 async with session.get(url, headers=headers, ssl=False) as resp: resp.raise_for_status() data = await resp.json() return data except (...) as err: # 保持原异常处理逻辑不变 pass
4. 检查并发连接限制
SSH动态隧道或目标服务器可能对并发连接数有限制,可尝试降低异步请求的并发量,或联系服务器管理员调整SSH服务的MaxSessions配置(若权限允许)。
内容的提问来源于stack exchange,提问作者user28513016
相关产品推荐
相关产品推荐

