这两天优化端口扫描脚本,在获取HTTP页面内容时,发现requests.get hang住了(之前httplib不会)。
requests.get 提供了超时参数timeout,但在实际使用过程中,仍发现get请求可能被hang住。
原因在于非HTTP Server,response中一直没有出现换行符\n,导致_read_status()在获取状态码的时候就hang住了。
一个简单的解决方法,可以创建新的线程,示例代码参考如下,这部分代码是无法直接工作的:
def do_get_thread(url, ret):
try:
headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 '
'(KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25',
'Range': 'bytes=0-10240',
'Connection': 'Close'}
ret.append(requests.get(url, headers=headers, timeout=(4, 30)))
except:
pass
def get_http_title(ip, port, service, log_queue):
if service.lower().find('https') >= 0 or service.lower().find('ssl') >= 0:
service = 'https'
else:
service = 'http'
url = '%s://%s:%s' % (service, ip, port)
msg = 'Get http title %s' % url
log_queue.put(msg)
try:
start_time = time.time()
ret = []
t = threading.Thread(target=do_get_thread, args=(url, ret))
t.daemon = True
t.start()
while t.isAlive():
if time.time() - start_time > 31:
log_queue.put('[get_http_title timed out] %s' % url)
return {}, ''
else:
time.sleep(1.0)
if not ret:
return {}, ''
resp = ret[0]
headers = resp.headers
m = re.search('<title>(.*?)</title>', resp.text, re.IGNORECASE)
http_title = m.group(1).strip() if m else ''
if http_title:
http_title = decode_response_text(http_title)
else:
http_title = resp.text.replace('\n', ' ').strip()[0:200]
return headers, http_title
except requests.exceptions.RequestException, e:
pass
except Exception, e:
log_queue.put('[get_http_title.exception] %s' % str(e))
return {}, ''
能给出具体的响应包么?
我这边用nc监听的话,然后不包含\n,超时依然有效
试试这个,应该能hang住:
http://s36.sq.pps.tv:9001
from requests import Request, Session
s = Session()
req = Request(‘GET’, “http://s36.sq.pps.tv:9001”)
prepped = req.prepare()
resp = s.send(prepped, timeout=5)
这样可以, 然后 catch 这个异常就可以.
—————————————————————————
ReadTimeout Traceback (most recent call last)
timeout需要大于30s,就可以复现了。
记得网络超时 分三种超时,还有一种是 一直推送的,导致无法关闭连接。
有python3的脚本吗