# -*- Mode: Python; tab-width: 4 -*-

import asyncore
import socket

class inet_server (asyncore.dispatcher):
	def __init__ (self, port=9999):
		asyncore.dispatcher.__init__ (self)
		self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
		self.bind ('', port)
		self.listen(10)
		
	def log (self, *ignore):
		pass

	def handle_accept (self):
		conn, addr = self.accept()
		server_channel (conn, addr)

class unix_server (asyncore.dispatcher):
	def __init__ (self, file='/tmp/speed_sock'):
		asyncore.dispatcher.__init__ (self)
		self.create_socket (socket.AF_UNIX, socket.SOCK_STREAM)
		self.bind (file)
		self.listen (10)

	def log (self, *ignore):
		pass

	def handle_accept (self):
		conn, addr = self.accept()
		server_channel (conn, addr)

class server_channel (asyncore.dispatcher):
	def __init__ (self, conn, addr):
		asyncore.dispatcher.__init__ (self)
		self.set_socket (conn)
		self.in_buffer = ''
		
	def log (self, *ignore):
		pass

	def handle_close (self):
		print 'unexpected close'
		self.close()

	def handle_connect (self):
		self.send ('Hello')

	def handle_read (self):
		self.in_buffer = self.in_buffer + self.recv(5)
		if self.in_buffer == 'Hello':
			self.close()

class async_client (asyncore.dispatcher):
	def __init__ (self, host='', port=9999):
		self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
		self.host = host
		self.port = port
		self.in_buffer = ''

	def go (self):
		self.connect (self.host, self.port)

	def log (self, *ignore):
		pass

	def handle_connect (self):
		pass

	def handle_read (self):
		data = self.recv(5)
		self.send (data)
		self.in_buffer = self.in_buffer + data

	def handle_close (self):
		print '%s.done()' % self
		self.close()

def synchronous_inet_client (host='', port=9999):
	s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
	s.connect (host, port)
	d = s.recv(5)
	s.send (d)

def synchronous_unix_client (file='/tmp/speed_sock'):
	s = socket.socket (socket.AF_UNIX, socket.SOCK_STREAM)
	s.connect (file)
	d = s.recv(5)
	s.send (d)

import time
class timer:
	def __init__ (self):
		self.start = time.time()
	def end (self):
		return (time.time() - self.start)

from asyncore import socket_map, poll
def loop (timeout=30.0):
	try:
		max = 0
		while socket_map:
			lsm = len(socket_map)
			if lsm > max:
				max == lsm
			poll (timeout)
	except KeyboardInterrupt:
		print 'max socket load',lsm

if __name__ == '__main__':
	import sys
	if '-u' in sys.argv:
		sock_type = 'unix'
	else:
		sock_type = 'inet'
	if '-s' in sys.argv:
		if sock_type == 'unix':
			unix_server()
		else:
			inet_server()
		loop()
	elif '-a' in sys.argv:
		# need to do this right...
		clients = map (lambda x: async_client('127.0.0.1'), range(1000))
		loop()
	else:
		if sock_type == 'unix':
			t = timer()
			for x in range(1000):
				synchronous_unix_client('/tmp/speed_sock')
			print t.end()
		else:
			t = timer()
			for x in range(1000):
				synchronous_inet_client('127.0.0.1')
			print t.end()

# Usage:
# in one window, invoke the server:
# $ python speed_test.py -s
# in another window, invoked the synchronous client test:
# $ python speed_Test.py
#
# To try out unix sockets, add a '-u' to each of the command
# lines.
#
# NT4.0 Workstation
# inet
# n=1000, time=18.03 seconds, ~55 transactions/second.
#
# Linux 2.0
# inet
# no sockets used,
# n=1000, time=8.25 seconds, ~121 t/s.
# with sockets in use (i.e., immediately after a previous run),
# about 16 seconds.
#
# unix
# n=1000, time=5.292 seconds, ~189 t/s.
