'''
test_web_server.py
- a script to test some basic metrics of a web server
Sample output:
D:\test_web_server>test_web_server.py -c10 -t15 -p987 -s -f/links.html
**************official results (1934):
connect request get some get rest total
-------- -------- -------- -------- --------
average: 0.02 0.00 0.02 0.05 0.08
median: 0.02 0.00 0.02 0.04 0.08
std dev: 0.02 0.00 0.01 0.02 0.03
minimum: 0.00 0.00 0.00 0.00 0.01
maximum: 0.47 0.03 0.22 0.27 0.55
approximate requests/second: 128.266347738
Total bytes transferred: 31779488
Bytes transferred per second: 2103208
In this particular run, it was downloading a 16281 byte file called
links.html from a web server running on the local host.
1.1
- Adds handling of new connection creation failure, includes such failures
into the connect time, and keeps a running total of failures.
- Added support for zero total results.
1.2
- Adds data transfer rates and totals.
1.3
- Adds support for Host: header for HTTP 1.1 servers.
'''
import sys
import socket
import threading
import Queue
import time
import optparse
results = Queue.Queue()
refused = 0L
transferred = 0L
reflock = threading.Lock()
endtime = None
def worker(host, port, file, include_host):
C = 0
D = 0
if include_host:
request = 'GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n'%(file, host)
else:
request = 'GET /%s HTTP/1.1\r\n\r\n'%file
t = [time.time()]
while time.time() < endtime:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host, port))
except:
C += 1
s.close()
continue
t.append(time.time())
s.sendall(request)
t.append(time.time())
try:
while 1:
_ = s.recv(65536)
if not _:
break
elif len(t) == 3:
t.append(time.time())
D += len(_)
except:
pass
s.close()
while len(t) < 5:
t.append(time.time())
t2 = []
x = t.pop(0)
while t:
y = t.pop(0)
t2.append(y-x)
x = y
results.put(t2)
t = [time.time()]
reflock.acquire()
global refused, transferred
refused += C
transferred += D
reflock.release()
def _stats(r):
#returns the median, average, standard deviation, min and max of a sequence
tot = sum(r)
avg = tot/len(r)
sdsq = sum([(i-avg)**2 for i in r])
s = list(r)
s.sort()
return s[len(s)//2], avg, (sdsq/(len(r)-1 or 1))**.5, min(r), max(r)
x = ('average: ', 'median: ', 'std dev: ', 'minimum: ', 'maximum: ')
def stats(r, e):
for i in r:
i.append(sum(i))
s = zip(*map(_stats, zip(*r)))
print " connect request get some get rest total"
print " -------- -------- -------- -------- --------"
for i,j in zip(x, s):
print i, "%8.2f %8.2f %8.2f %8.2f %8.2f"%j
print "approximate requests/second: ", len(r)/float(e)
if __name__ == '__main__':
usage = "usage: \%prog -c<count> -t<time> -H<host> -p<port> -f<file>"
parser = optparse.OptionParser(usage)
parser.add_option('-c', '--count', dest='count', type='int',
help='Number of simultaneous threads (default 5)', default=5,
action='store')
parser.add_option('-t', '--time', dest='time', type='int',
help='At least how long in seconds to run the test (default 60)',
default=60, action='store')
parser.add_option('-H', '--host', dest='host',
help='The host of the web server (default localhost)',
default='localhost', action='store')
parser.add_option('-i', '--include', dest='include', action='store_true',
help='if passed, will include Host: header as specified with -H in the request',
default=False)
parser.add_option('-p', '--port', dest='port', type='int',
help='Port to connect to on (default 80)', default=80, action='store')
parser.add_option('-f', '--file', dest='file',
help='the file to download', action='store')
parser.add_option('-s', '--single', dest='single', action='store_true',
help='if passed, will only produce one table of output', default=False)
options, args = parser.parse_args()
if options.file is None:
parser.error('need file to fetch')
starttime = time.time()
endtime = starttime + options.time
for i in xrange(options.count):
threading.Thread(target=worker,
args=(options.host, options.port,
options.file.lstrip('/\\'), options.include)).start()
if not options.single:
while endtime > time.time():
time.sleep(.1)
r = []
while results.qsize():
r.append(results.get())
rc = len(r)
if r:
print "**************official results (%i):"%(len(r))
stats(r, options.time)
while threading.activeCount() > 1:
time.sleep(.1)
r = []
while results.qsize():
r.append(results.get())
if r:
print "**************late finishers (%i):"%(len(r))
stats(r, time.time()-endtime)
print "effective requests/second: ", (rc+len(r))/(time.time()-starttime)
else:
while threading.activeCount() > 1:
time.sleep(.1)
r = []
while results.qsize():
r.append(results.get())
if r:
print "**************official results (%i):"%(len(r))
stats(r, time.time()-starttime)
print "Total bytes transferred: ", transferred
print "Bytes transferred per second:", int(transferred/(time.time()-starttime))
if refused:
print "Connections refused: ", refused