如何解决Windows下Python代码的WinError 10048套接字错误?
Windows下Python网络请求WinError 10048问题解决
问题背景
Ubuntu上运行正常的Python网络请求代码,迁移到Windows后反复抛出错误:OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted。
已尝试的方法
- 常规requests.post写法:
response = requests.post(url_get, headers=headers, json=data) - Stream模式requests.post写法:
with requests.post(url_get, headers=headers, json=data, stream=True) as r: response = r - 使用http.client.HTTPSConnection:
http.client.HTTPSConnection(url) - 带timeout参数的HTTPSConnection写法:
http.client.HTTPSConnection(url, timeout=10) - 配置重试适配器:
session = requests.Session() retry = Retry(connect=8, backoff_factor=2) adapter = HTTPAdapter(max_retries=retry) session.mount('https://', adapter)
解决方案
Windows对套接字地址复用的限制比Linux严格,默认TIME_WAIT状态的端口不会快速释放,短时间大量请求会耗尽可用端口。以下是无需sleep、额外timeout或过度重试的解决方法:
自定义套接字适配器实现地址复用
通过修改requests的底层连接池,强制开启套接字地址复用选项,同时优化连接管理:
import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry import socket from urllib3.connection import HTTPConnection from urllib3.connectionpool import HTTPConnectionPool class ReusableHTTPConnection(HTTPConnection): def connect(self): super().connect() # 开启地址复用,允许重用TIME_WAIT状态的端口 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) try: # 尝试开启端口复用(部分Windows环境支持) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) except AttributeError: pass class ReusableHTTPConnectionPool(HTTPConnectionPool): ConnectionCls = ReusableHTTPConnection class ReusableHTTPAdapter(HTTPAdapter): def init_poolmanager(self, connections, maxsize, block=False, **pool_kwargs): self.poolmanager = requests.packages.urllib3.poolmanager.PoolManager( num_pools=connections, maxsize=maxsize, block=block, connection_pool_class=ReusableHTTPConnectionPool, **pool_kwargs ) # 初始化session并挂载适配器 session = requests.Session() # 配置合理的重试策略(避免过度重试) retry = Retry( connect=3, read=2, backoff_factor=1, allowed_methods=["POST"] ) adapter = ReusableHTTPAdapter(max_retries=retry) session.mount('https://', adapter) session.mount('http://', adapter) # 使用session发起请求 response = session.post(url_get, headers=headers, json=data)
额外优化建议
- 调整连接池
maxsize参数:根据请求频率设置合理值(如10-20),避免短时间创建过多连接 - 确保请求完成后正确释放资源:使用
session.close()或上下文管理器with requests.Session() as session:管理session生命周期
内容的提问来源于stack exchange,提问作者anon.for
相关产品推荐
相关产品推荐

