0X00 背景
在一次恰巧查看vps时,发现vps存在大量的TIME_WAIT状态的连接(几百个吧也不是很大量),发现是某Python进程引起,甚觉奇怪。当时VPS上只跑有SSR和一个火币K线爬虫。当然我第一反应是怀疑到SSR,但转念一想,如果是SSR,我的梯子估计早就塌了,故怀疑到爬虫。以至后来引出了一些关于http keep-alive,tcp长连接和python requests的一些思考。
0X01 起因
问题的原因在于,火币在github上提供的Python SDK中,直接使用requests.get()和requests.post()。导致每次请求都会不断建/拆连接,作为主动关闭方,频繁的建/拆tcp连接,必定导致大量的TIME_WAIT。
了解到起因后修改了一下火币的SDK,利用request.session来保持长链接。效果很棒,不但减少了TIME_WAIT的产生,还提升了请求速度。
修改之前:
use 1.104477 seconds
修改之后:
use 0.385232 seconds
0X02 反问
找到了问题原因,还修改了火币SDK分享给了群里的韭菜们。开开心心的扭头跟叶老师分享我的成果。但叶老师反问了一个很专业的问题,你说的长链接,是说的那个keep-alive么?
长连接?keep-alive? 恩,我也不知道是哪种,不过可以抓包看一下。但抓包之前要先抛出假设。经过我和叶老师激烈的讨(si)论(bi)我做了如下假设:
1、http不带有keep-alive的话,服务器再完成请求后会主动断开连接
2、requests.get() 发起的http请求不带有keep-alive,所以请求完成后,服务器会把连接接断开。
3、session.get() 发起的http请求带有keep-alive,请求完成后服务器非意外情况不会断开连接,由客户端控制连接长短
下面就是抓包
第一个场景:调用requests.get(),观察http是否带有keep-alive,服务器 or 客户端 主动断开连接
源码如下:
1 | import time |
这是我访问www.163.com的包。可以看到requests.get()里面其实是带有keep-alive的。跟我预想的不太一样。

再看一下连接断开的包,其实也是客户端主动断开的。

恩,看来有keep-alive的时候确实服务器不会主动断开链接。
那我们尝试一下把keep-alive干掉,服务器会不会主动断开连接?
因为用的是requests库,而且keep-alive是默认加上的,只能去库里面把代码注释掉了。
注释位置如下:requests/utils.py :741

注释掉代码后,再次发起请求看一下,确实没有了keep-alive

但是好像还是客户端断开的连接。为什么呢?后来查了查可能跟nginx的特性有关,这个后续再专门来研究吧。

总之到此为止,前两个假设都已经错误了。不过倒是可以确定一点。request.get会自己断开连接,确实是短连接,哈哈。