为何requests.Session上下文管理器未实际关闭TCP连接?
关于requests Session上下文管理器与TCP连接的疑问解答
一、Session上下文管理器的核心意义
用with语句管理Session,核心目的是确保Session的资源被及时、正确地回收,而非直接控制TCP连接的关闭:
- 退出
with块时,Session会自动调用close()方法,该方法会关闭所有底层的HTTP适配器(requests基于urllib3实现),清理连接池中的空闲连接,释放相关的系统资源(如文件句柄)。 - 这避免了因Session对象未被显式关闭,导致资源泄漏或依赖Python垃圾回收机制延迟清理的问题,是一种规范的资源管理方式。
你看到TCP连接仍保持一段时间,是因为HTTP/1.1默认启用长连接(Keep-Alive),即使Session的连接池被清理,已建立的TCP连接可能会进入系统层面的TIME_WAIT状态(TCP协议的正常机制,确保所有数据包都被处理),或者连接池的关闭逻辑不会强制中断正在保持的长连接。
二、如何在上下文结束后立即关闭TCP连接
如果需要强制在Session上下文结束后立即断开TCP连接,可以通过以下两种方式实现:
1. 请求时禁用长连接
在请求头中添加Connection: close,告知服务器处理完请求后立即关闭连接:
import requests with requests.Session() as s: r = s.get("http://172.17.0.3:8000", headers={"Connection": "close"})
这种方式会让服务器主动发送FIN包,客户端收到后会断开TCP连接,不会进入长连接等待状态。
2. 手动清理所有连接池
在退出with块前,手动遍历并关闭Session的所有适配器连接池:
import requests with requests.Session() as s: r = s.get("http://172.17.0.3:8000") # 强制关闭所有适配器的连接池 for adapter in s.adapters.values(): adapter.close()
适配器的close()方法会直接关闭连接池中的所有空闲连接,强制终止长连接。
三、是否推荐立即关闭TCP连接
不推荐常规场景下刻意强制关闭TCP连接,原因如下:
- HTTP长连接是为了优化性能:复用已建立的连接可以避免重复的TCP握手、慢启动等开销,尤其在多次请求同一服务器时效率更高。
TIME_WAIT状态是TCP协议的正常机制:系统会自动在2MSL(约1-2分钟)后回收这些连接,不会永久占用资源。只有在短时间内创建大量短连接,导致端口资源耗尽的极端场景下,才需要考虑强制关闭连接。
如果你的业务仅需单次请求,且对连接回收有严格要求,可以使用上述方式关闭;否则依赖Session上下文管理器的默认清理逻辑即可。
内容的提问来源于stack exchange,提问作者Simon Ernesto Cardenas Zarate
相关产品推荐
相关产品推荐

