我想在我们的其中一台Web服务器上进行一些性能测试,以了解服务器如何处理大量持久连接。不幸的是,我对HTTP和Web测试不是很熟悉。这是到目前为止我已经获得的Python代码:
import http.client import argparse import threading def make_http_connection(): conn = http.client.HTTPConnection(options.server, timeout=30) conn.connect() if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("num", type=int, help="Number of connections to make (integer)") parser.add_argument("server", type=str, help="Server and port to connect to. Do not prepend \'http://\' for this") options = parser.parse_args() for n in range(options.num): connThread = threading.Thread(target = make_http_connection, args = ()) connThread.daemon = True connThread.start() while True: try: pass except KeyboardInterrupt: break
我的主要问题是: 如何保持这些连接的生命? 我设置了很长的超时时间,但这是一种非常粗糙的方法,我甚至不确定它是否会影响连接。是否只是偶尔偶尔请求一两个字节?
(此外,与while True:我代码末尾的丑陋块相比,还有一个更好的过程来等待键盘中断吗?)
while True:
urllib.request不支持持久连接。'Connection: close'代码中有硬编码。但http.client部分支持持久连接(包括旧版http / 1.0 keep- alive)。因此,问题标题可能会引起误解。
urllib.request
'Connection: close'
http.client
keep- alive
我想在我们的其中一台Web服务器上进行一些性能测试,以了解服务器如何处理大量持久连接。不幸的是,我对HTTP和Web测试不是很熟悉。
您可以使用现有的http测试工具(例如slowloris和httperf)来代替自己编写。
如何使这些连接保持活动状态?
要关闭http / 1.1连接,客户端应明确指定Connection: close标头,否则服务器会认为该连接是持久的(尽管它可能随时关闭它,直到它尝试读取/写入连接时才http.client知道该连接)。
Connection: close
conn.connect()几乎立即返回,并且线程结束。要强制每个线程维护与服务器的http连接,您可以:
conn.connect()
import time def make_http_connection(*args, **kwargs): while True: # make new http connections h = http.client.HTTPConnection(*args, **kwargs) while True: # make multiple requests using a single connection try: h.request('GET', '/') # send request; make conn. on the first run response = h.getresponse() while True: # read response slooowly b = response.read(1) # read 1 byte if not b: break time.sleep(60) # wait a minute before reading next byte #note: the whole minute might pass before we notice that # the server has closed the connection already except Exception: break # make new connection on any error
注意:如果服务器返回,'Connection: close'则每个连接只有一个请求。
(另外,一个无关紧要的问题是,比我的代码末尾的丑陋的True:block更好的等待键盘中断的程序吗?)
要等待所有线程完成或KeyboardInterrupt发生,您可以:
KeyboardInterrupt
while threads: try: for t in threads[:]: # enumerate threads t.join(.1) # timeout 0.1 seconds if not t.is_alive(): threads.remove(t) except KeyboardInterrupt: break
或类似这样的东西:
while threading.active_count() > 1: try: main_thread = threading.current_thread() for t in threading.enumerate(): # enumerate all alive threads if t is not main_thread: t.join(.1) except KeyboardInterrupt: break
后者可能由于各种原因而无法工作,例如,如果存在虚拟线程,例如以C扩展名启动的线程而不使用threading模块。
threading
parallel.futures.ThreadPoolExecutor提供了比threading模块更高的抽象级别,并且可以隐藏一些复杂性。
您可以在单个线程中同时打开多个连接,而不是使用每个连接模型的线程,例如,使用requests.async或gevent直接打开。
requests.async
gevent