#!/usr/bin/env python import sys import socket import select import empty import thr import dbg readable = lambda f, tmout=0: select.select( [ f ], [], [], tmout )[ 0 ] == [ f ] def recv( f, bufmax=4*1024, tmout=3.0 ): if not readable( f, tmout ): return None # time out s = f.recv( bufmax ).decode( 'utf-8' ) return s # '' is EOF def sendall( f, s ): ret = True try: f.sendall( s.encode( 'utf-8' ) ) except: ret = False return ret def srv_new( port, cb=None, bufmax=4*1024, tmout=3.0, kill_word='kill_srv' ): ss = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) ss.setsockopt( socket.SOL_SOCKET, socket.SO_REUSEADDR, 1 ) ss.bind( ( '', port ) ) ss.listen( 5 ) e = empty.new() e.cb = cb th_dic = {} def th_start( th, f ): th_dic[ th ] = f thr.ths.start( th ) def th_stop( th ): th.quit_ev.set() if th in th_dic: f = th_dic.pop( th ) f.close() def func_cs( args ): ( th, cs ) = args s = recv( cs, bufmax, tmout ) if s is None: return # tmout if not s: th.quit_ev.set() return if s == kill_word: stop() return r = 'not set callback' if e.cb: r = e.cb( s ) if r: if not sendall( cs, r ): dbg.out( 'err send "{}"'.format( r ) ) def func_ss(): if not readable( ss, 3.0 ): return if not is_alive(): return ( cs, adr ) = ss.accept() args = [] th = thr.loop_new( func_cs, ( args, ) ) args.append( th ) args.append( cs ) th_start( th, cs ) th_srv = thr.loop_new( func_ss ) th_start( th_srv, ss ) def stop(): for th in th_dic.keys(): th_stop( th ) def is_alive(): return not th_srv.quit_ev.is_set() def wait(): th_srv.quit_ev.wait() return empty.add( e, locals() ) def cli_new( port, host='localhost', bufmax=4*1024, tmout=3.0, kill_word='kill_srv' ): cs = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) e = empty.new() e.is_conn = False def conn(): if not e.is_conn: try: cs.connect( ( host, port ) ) e.is_conn = True except: pass return e.is_conn def send_recv( s ): if not conn(): return 'err connect' if not sendall( cs, s ): return 'err send' if s == kill_word: return '' r = recv( cs, bufmax, tmout ) if r is None: return 'tmout recv' return r def close(): if e.is_conn: cs.close() e.is_conn = False def kill_srv(): r = send_recv( kill_word ) close() return r return empty.add( e, locals() ) def run(): argv = sys.argv[ 1 : ] port = 1234 k = 'port=' for i in range( len( argv ) ): if argv[ i ].startswith( k ): s = argv.pop( i ) port = int( s[ len( k ) : ] ) break s = 'srv' if argv: s = argv.pop( 0 ) if s == 'srv': cb = lambda s: s.upper() srv = srv_new( port, cb ) srv.wait() return o = cli_new( port ) while s: r = o.send_recv( s ) if r: dbg.out( r ) s = argv.pop( 0 ) if argv else '' if __name__ == "__main__": run() # EOF