PycURL HTTPS会话频繁断开求助:如何维持长连接提升通信速度
解决HTTP/1.1连接复用问题,避免每次请求重建会话
从你的日志和代码来看,核心问题是虽然设置了keep-alive,但请求头未正确发送,且会话复用的使用方式有误,导致每次POST后TCP连接无法复用,必须重新建立(耗时3秒)。以下是具体修复步骤:
1. 修正请求头的设置顺序
你的post函数中,先调用session.setopt(session.HTTPHEADER, ...)再修改header['Connection'] = 'keep-alive'——这会导致keep-alive头根本没被发送到服务器。服务器未收到keep-alive请求,自然会在响应后关闭连接。
修改后的post函数:
def post(url, file, header, session): buffer = BytesIO() # 先添加keep-alive相关头到字典,再生成请求头列表 header['Connection'] = 'keep-alive' header['Keep-Alive'] = 'timeout=500, max=1000' # 先设置请求头,再配置其他选项 session.setopt(session.HTTPHEADER, [f"{k}: {v}" for k, v in header.items()]) session.setopt(session.URL, url) session.setopt(session.POSTFIELDS, file) session.setopt(session.WRITEDATA, buffer) try: session.perform() response_code = session.getinfo(pycurl.RESPONSE_CODE) response_body = buffer.getvalue().decode('utf-8') except pycurl.error as e: response_code = None response_body = f"Request failed: {e}" return response_body
2. 必须复用同一个Curl会话实例
所有POST请求必须使用同一个create_session()返回的session对象,不能每次请求都重新创建会话。示例用法:
# 仅初始化一次会话 client_session = create_session() # 多次复用该会话发送请求 resp1 = post("https://172.21.51.191/rest/login.cgi", login_data, login_header, client_session) resp2 = post("https://172.21.51.191/rest/status.cgi", status_data, status_header, client_session) # 所有请求完成后再关闭会话 client_session.close()
3. 增强TCP连接的存活配置
在create_session中添加TCP keep-alive相关选项,强制维持TCP连接:
def create_session(): session = pycurl.Curl() session.setopt(session.COOKIEFILE, "") # 启用cookie处理 session.setopt(session.COOKIEJAR, "cookies.txt") # 保存cookie到文件 session.setopt(session.SSL_VERIFYPEER, 0) session.setopt(session.SSL_VERIFYHOST, 0) session.setopt(session.VERBOSE, True) session.setopt(session.SSL_SESSIONID_CACHE, 1) # 启用SSL会话缓存 session.setopt(session.HTTP_VERSION, pycurl.CURL_HTTP_VERSION_1_1) # 添加TCP keep-alive配置,维持连接 session.setopt(session.TCP_KEEPALIVE, 1) session.setopt(session.TCP_KEEPIDLE, 60) # 60秒后开始发送保活包 session.setopt(session.TCP_KEEPINTVL, 10) # 每10秒发送一次保活包 # 明确允许连接复用(默认允许,但显式设置更稳妥) session.setopt(session.FORBID_REUSE, 0) session.setopt(session.FRESH_CONNECT, 0) return session
4. 处理响应chunked编码的遗留数据问题
日志中出现Leftovers after chunking: 7 bytes,说明服务器返回的chunked编码响应存在未处理的残留数据,curl可能因此判定连接不可用而放弃复用。可以尝试强制关闭自动解码:
# 在create_session中添加 session.setopt(session.HTTP_TRANSFER_DECODING, 0)
修正头设置后,该问题大概率会自动消失。
5. 服务器不支持keep-alive的 fallback方案
如果上述修改后仍无法复用TCP连接(比如服务器强制返回Connection: close),可以依赖SSL会话复用减少握手时间:
- 确保
SSL_SESSIONID_CACHE已设置为1(你已添加) - 复用同一个Curl会话,curl会自动缓存SSL会话ID,下次连接时直接复用,避免完整的SSL握手(耗时会远低于3秒)
内容的提问来源于stack exchange,提问作者Lorenzo Ruzza
相关产品推荐
相关产品推荐

