python - Twisted TCP server with a Tkinter GUI -
recently i've been experimenting twisted (python library) in attempt make tcp chat server/client. had server running nicely when tried add tkinter-based gui server, things got weird. user connects server, message sent gui. however, somewhere along way goes wrong , long-winded error comes up, gist of tkinter ran out of stack space because of infinite loop. i've put code below. function having trouble app.write(text) , user.connectionmade(*args) other function in user class attempts print text gui.
from twisted.internet.protocol import serverfactory, protocol twisted.internet import reactor os import path import yaml import threading tkinter import * __version__ = '' __author__ = '' class user(protocol): def connectionmade(self,*args): self.gui.write('new connection %s' % (self.addr.host)) self.transport.write('username: ') def connectionlost(self,reason): self.gui.write('connection lost %s' % (self.addr.host)) if not self.name == none: msg = '%s has disconnected\r\n' % (self.name) self.gui.write(msg.rstrip()) self.toall(msg) del self.users[self.name] def datareceived(self,data): if data == '\x08': if len(self.text) > 0: self.text = self.text[:-1] return elif not data.endswith('\r\n'): self.text += data return if self.name == none: self.setname(self.text) else: self.handle(self.text) self.text = '' def handle(self,data): if not data.startswith('/'): self.chat(data) else: self.gui.write('%s executed command %s' % (self.name, data)) if data in ['/help','/h']: self.cmdhelp() elif data in ['/list','/l']: self.userlist() elif data in ['/motd','/m']: self.sendmotd() elif data in ['/ping','/p']: self.transport.write('pong!\r\n') else: self.transport.write('unrecognized command %s\r\n' % (data)) def cmdhelp(self): x = ['\r\ncommands:',\ '/motd,/m - display motd',\ '/list,/l - display list of online users',\ '/help,/h - display list\r\n'] item in x: self.transport.write(item+'\r\n') def sendmotd(self): self.transport.write('\r\nmotd: %s\r\n\r\n' % (self.motd)) def userlist(self): self.transport.write('\r\ncurrently online: server,%s\r\n\r\n' % (','.join(item item in self.users))) def setname(self,name): if self.users.has_key(name) or name.lower() == 'server': self.transport.write('that username in use!\r\nusername: ') elif ' ' in name: self.transport.write('no spaces allowed in usernames!\r\nusername: ') elif name == '': self.transport.write('you must enter username!\r\nusername: ') else: self.users[name] = self self.name = name self.gui.write('new user registered %s' % (name)) self.toall('%s has connected' % (self.name)) self.transport.write('\nsuccessfully logged in %s\r\n\r\n' % (name)) self.sendmotd() def toall(self,msg): name,protocol in self.users.iteritems(): if not protocol == self: protocol.transport.write(msg) def chat(self,data): to_self = '<%s (you)> %s\r\n' % (self.name, data) to_else = '<%s> %s\r\n' % (self.name, data) self.gui.write('[chat] - %s' % (to_else.rstrip())) self.transport.write(to_self) self.toall(to_else) def __init__(self,addr=none,users=none,motd=none,master=none): self.name = none self.addr = addr self.users = users self.motd = motd self.text = '' self.factory = master self.gui = self.factory.app self.kicked = false class app(frame): def write(self,text): self.display.insert(end,text+'\n') def clear(self,event=none): self.display.delete(1.0,end) def userlist(self): self.write('currently online: server,%s' % (','.join(item item in self.factory.users))) def handle(self,event=none): msg = self.entry.get() self.entry.delete(0,end) if not msg.startswith('/'): self.send(msg) elif msg in ['/cls','/clear','/clr','/c']: self.clear() elif msg in ['/list','/l']: self.userlist() elif msg in ['/exit']: self.kill() else: self.write('unrecognized command \'%s\'' % (msg)) def send(self,msg,event=none): item in self.factory.users: self.factory.users[item].transport.write('<server> %s\r\n' % (msg)) self.write('[chat] - <server> %s' % (msg)) def kill(self): self.write('stopping server...') reactor.stop() self.write('gui says guidbye! :(') self.quit() def __init__(self,master,factory): frame.__init__(self,master) self.grid(row=0,sticky=n+e+s+w) self.columnconfigure(0,weight=1) self.rowconfigure(0,weight=1) self.display = text(self) self.display.grid(row=0,sticky=n+e+s+w) self.yscroll = scrollbar(self,command=self.display.yview) self.yscroll.grid(row=0,column=1,sticky=n+s) self.display.config(yscrollcommand=self.yscroll.set) self.entry = entry(self) self.entry.grid(row=1,sticky=e+w) self.master = master self.master.wm_title('tcp chat server v%s' % (__version__)) self.factory = factory self.motd = '' self.port = 0 self.entry.bind('<return>',self.handle) self.master.protocol('wm_delete_window',self.kill) self.write('tcp chat server v%s' % (__version__)) self.write('by %s\n' % (__author__)) self.write('server running on port %s' % (self.factory.port)) class main(serverfactory): def buildprotocol(self,addr): return user(addr=addr,users=self.users,motd=self.motd,master=self) def start(self): self.root = tk() self.root.columnconfigure(0,weight=1) self.root.rowconfigure(0,weight=1) self.app = app(self.root,self) self.app.mainloop() def __init__(self,motd,port): self.users = {} self.motd = motd self.port = port self.tk_thread = threading.thread(target=self.start) self.tk_thread.start() if not path.isfile('config.yml'): open('config.yml','w').write('port: 4444\nmotd: no motd set!') open('config.yml','r') f: dump = yaml.load(f.read()) motd = dump['motd'] port = dump['port'] reactor.listentcp(port,main(motd,port)) reactor.run()
everything else running expected, , when comment out app.write('') statements, program runs expected (sans gui , server-side messages). i've been using windows test program use
telnet localhost 4444
to run client.
twisted has specialised support tkinter.
from tkinter import * twisted.internet import tksupport, reactor root = tk() # install reactor support tksupport.install(root) # @ point build tk app usual using root object, # , start program "reactor.run()", , stop # "reactor.stop()".
Comments
Post a Comment