#interactive run -i import threading import Queue import functools class GenThread( threading.Thread, Queue.Queue ): _taskid= 0 def __init__( self, *ar, **kw ): threading.Thread.__init__( self, *ar, **kw ) Queue.Queue.__init__( self ) self.setDaemon( True ) self.start() self._doneevents= {} def run( self ): while 1: id, fun, ar, kw= self.get() self._= fun( *ar, **kw ) self._doneevents[id].set() if self._: self._print( self._ ) def me( self, fun, *ar, **kw ): id= GenThread._taskid GenThread._taskid+= 1 self.put( ( id, fun, ar, kw ) ) self._doneevents[ id ]= e= threading.Event() return e def _print( self, *ar, **kw ): print( self.getName(), *ar, **kw )
for i in range( 10 ): exec( 'th%i= GenThread()'% i ) import socket host= socket.socket( socket.AF_INET, socket.SOCK_STREAM ) host.bind( ( '', 8000 ) ) th1.me( host.listen, 1 ) _acc= th1.me( host.accept ) cli= socket.socket( socket.AF_INET, socket.SOCK_STREAM ) th2.me( cli.connect, ( 'localhost', 8000 ) ) _acc.wait() conn= th1._[0] ConnClose= object() class IncompleteTransmission( Exception ): pass def _draintilclose( conn, understandfun= None ): while 1: _preamb= '' while 1: _data= conn.recv( 1 ) if not _data: conn.close() return ConnClose if _data== b'\x00': break _preamb+= _data.decode() _len= int( _preamb, 16 ) _lenleft= _len _curmsg= bytearray() while _lenleft: _data= conn.recv( min( 4096, _lenleft ) ) if not _data: raise IncompleteTransmission _curmsg.extend( _data ) _lenleft-= len( _data ) assert len( _curmsg )== _len if None is not understandfun: understandfun( _curmsg ) def _dressandsend( sck, msg ): _preamble= hex( len( msg ) )[2:]+ '\x00' _dressed= bytes( _preamble, 'ascii' )+ msg _lenleft= len( _dressed ) while _lenleft: _sent= sck.send( _dressed[-_lenleft:] ) _lenleft-= _sent th1.me( _draintilclose, conn, th1._print ) th2.me( _draintilclose, cli, th2._print ) This is cool! Set up a socket and listen 'til close on one thread, print output by default as complete messages are received. Listen 'til close, same, on another, th1, th2 respectively. Roughly off the console: >>> _dressandsend( conn, b'abc' ) Thread-2 bytearray(b'abc') >>> _dressandsend( cli, b'def' ) Thread-1 bytearray(b'def') Rearranged the '>>>'. It's damn annoying. Probably a specialized stdout to detect when in a prompt and add extra newline, maybe modified GenThread._print. Someone go replace hex with base255 and conn.recv( 1 ) with conn.recv( 2 ). Should take any length-- base256 over hex is just a factor of 2, and still O( log( message length ) ). >>> dir() ['ConnClose', 'GenThread', 'IncompleteTransmission', 'Queue', '__builtins__', '__doc__', '__name__', '__package__', '_acc', '_draintilclose', '_dressandsend', 'cli', 'conn', 'functools', 'host', 'i', 'socket', 'th1', 'th2', 'th3', 'th4', 'th5', 'th6', 'th7', 'th8', 'th9', 'threading'] -- http://mail.python.org/mailman/listinfo/python-list