Multithreaded Telnet sessions

Pierre-Frédéric Caillaud peufeu at free.fr
Wed Jun 30 18:39:02 CEST 2004


I like single-threaded asynchronous network stuff, but programming state  
machines is a pain.
Here is a guess at how to do it with pseudo coroutines implemented by  
hacking with yield.
If your stuff can be implemented asynchronously (use module asynchat) you  
can easily have hundreds of simultaneous connections.

#	fast single-threaded queue
class stQueue( object ):
	class QueueEmptyError( KeyError ):
		pass
		
	def __init__(self):
		self._in = 0;
		self._q = {}
	
	def put(self, obj):
		self._q[self._in] = obj
		self._in += 1
	
	def get(self):
		if self._q:		return self._q.pop( self._in - len(self._q) )
		else:			raise self.QueueEmptyError
	
	def qsize(self):
		return len( self._q )
	
	def __nonzero__(self):
		return bool(self._q)

# receiver class, could be a socket to send data
class stReceiver( object ):
	def __init__(self,name):
		self.name = name
	def process( self, data ):
		print self.name, ':', data

# stupid coroutines implemented with yield
class asyncSync( object ):
	def __init__( self, receiver ):
		self.inqueue = stQueue()
		self.receiver = receiver
	
	# we expect messages where
	# message=0 print "hello"
	# message=1 get another message and print it
	# message=2 get an integer N, get N messages, print them
	# message=3 die
	def run(self):
		while 1:
			while not self.inqueue:		# try to get a message
				yield None			# come back here newt time if no message
			msg = self.inqueue.get()
			
			if msg==0:
				self.receiver.process( '(0) hello' )
			elif msg==1:
				while not self.inqueue:
					yield None
				self.receiver.process( "(1) print a message : %s" % self.inqueue.get()  
)
			elif msg==2:
				while not self.inqueue:
					yield None
				nmessages = self.inqueue.get()
				self.receiver.process( "(2) waiting for %d messages" % nmessages )
				while self.inqueue.qsize() < nmessages:
					yield None
				for i in range(nmessages):
					self.receiver.process( "(2) print a message (%d/%d) : %s" %  
(i,nmessages,self.inqueue.get()) )
			elif msg==3:
				break
		
a = asyncSync( stReceiver( 'thread a' ))
ar = a.run()

ma = iter([ 0, 1, 'yikes', 2, 3, 'i', 'am', 'here', 2, 4, 'i', 'am',  
'still', 'here', 0, 3 ])


print ar.next()
a.inqueue.put( ma.next() )	# these lines send a message to the object a
print ar.next()			# these trigger some processing in a.run
a.inqueue.put( ma.next() )
print ar.next()
a.inqueue.put( ma.next() )	# these lines are interleaved in random order  
just to show it works
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
print ar.next()
print ar.next()
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
print ar.next()
a.inqueue.put( ma.next() )
a.inqueue.put( ma.next() )
print ar.next()
a.inqueue.put( ma.next() )
print "We should crash here"
print ar.next()











More information about the Python-list mailing list