python gui界面 tcp_带Tkinter GUI的Twisted TCP服务器

本文档介绍了如何使用Python的Twisted库创建TCP服务器,并结合Tkinter实现GUI界面。作者在尝试将GUI与TCP服务器集成时遇到了问题,导致Tkinter因无限循环耗尽堆栈空间。代码示例包括User类、App类和Main类,用于处理用户连接、发送和接收数据。问题主要集中在User类的`connectionMade`、`dataReceived`和与GUI交互的函数中。
摘要由CSDN通过智能技术生成

最近我一直在尝试使用Twisted(python库)来制作TCP聊天服务器/客户端。我让服务器运行得很好,但是当我试图向服务器添加基于Tkinter的GUI时,事情变得很奇怪。一旦用户连接到服务器,就会向GUI发送一条消息。然而,在这个过程中,某个地方出了问题,出现了一个冗长的错误,其要点是Tkinter由于一个无限循环而耗尽了堆栈空间。我把我的代码放在下面。我遇到麻烦的函数是应用程序写入(文本)和User.connectionMade(*args)以及User类中尝试将文本打印到GUI的任何其他函数。在from twisted.internet.protocol import ServerFactory, Protocol

from twisted.internet import reactor

from os import path

import yaml

import threading

from Tkinter import *

__version__ = ''

__author__ = ''

class User(Protocol):

def connectionMade(self,*args):

self.gui.write('New connection from %s' % (self.addr.host))

self.transport.write('Username: ')

def connectionLost(self,reason):

self.gui.write('Connection lost with %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 the MOTD',\

'/list,/l - Display a list of online users',\

'/help,/h - Display this list\r\n']

for 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 for item in self.users)))

def setName(self,name):

if self.users.has_key(name) or name.lower() == 'server':

self.transport.write('That username is in use!\r\nUsername: ')

elif ' ' in name:

self.transport.write('No spaces are allowed in usernames!\r\nUsername: ')

elif name == '':

self.transport.write('You must enter a username!\r\nUsername: ')

else:

self.users[name] = self

self.name = name

self.gui.write('New user registered as %s' % (name))

self.toAll('%s has connected' % (self.name))

self.transport.write('\nSuccessfully logged in as %s\r\n\r\n' % (name))

self.sendMotd()

def toAll(self,msg):

for name,protocol in self.users.iteritems():

if not protocol == self:

protocol.transport.write(msg)

def chat(self,data):

to_self = ' %s\r\n' % (self.name, data)

to_else = ' %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 for 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):

for item in self.factory.users: self.factory.users[item].transport.write(' %s\r\n' % (msg))

self.write('[CHAT] - %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('',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 currently 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!')

with open('config.yml','r') as f:

dump = yaml.load(f.read())

motd = dump['motd']

port = dump['port']

reactor.listenTCP(port,Main(motd,port))

reactor.run()

其他一切都按预期运行,当我评论出应用程序写入('')语句,程序按预期运行(sansgui和服务器端消息)。我一直在用Windows来测试这个程序,所以我用

^{pr2}$

运行客户端。在

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
服务端: 服务端程序启动之后弹出窗口,管理员输入IP、端口等信息之后点击启动按钮,服务器启动,服务端窗口自动关闭,之后跳转至服务端信息展示界面,包含用户上线提醒,用户发送信息记录展示。 客户端: 客户端程序启动之后,需要弹出登录界面,当用户成功输入昵称、密码、端口、IP等信息(考虑到用户权限问题,本程序在后台默认有固定IP、端口,)用户只需输入昵称、密码(密码用于后期连接数据库时用来匹配数据库存储的用户信息)。当用户成功输入用户名。昵称、密码等信息客户端登录成功跳转至用户进行端对端的聊天界面。聊天界面大致分为聊天记录展示界面,在线好友信息界面以及用户发送信息处。用户在发送消息处输入想要发送的文本消息,选择在线好友中的好友昵称点击选择好友即可选中您要发给的好友昵称,然后点击发送按钮,即可将消息发送给所选择的好友,同时将信息展示在自己的聊天界面中的聊天记录处 2.2. 功能要求 §2.2.1服务端功能要求: 当管理员输入服务器IP、以及端口等信息之后点击启动按钮之后,服务端正常启动之后,需要保持一直开机状态满足所有用户不论在何时登录之后都能进行与好友之间的聊天交流等,同时服务端还要满足监控用户登录信息,不同用户登录客户端之后,服务器后台能够看到某某客户上线了等提示信息。用于服务端查看好友在线状态同时作为服务器,还要能够监控用户的聊天记录,用于监控用户不能发送一些不利言论,从而将其用户及时作封号处理。阻止其传播一些不健康的言论。 §2.2.2客户端要求: 用户在登录界面输入昵称、密码等信息之后成功登录之后,进行窗口之间的跳转,由登录窗口跳转至进行用户之间的聊天窗口,之前的登录窗口也要随之消失。在聊天窗口之中用户需要根据好友在线信息情况选择自己想要与其进行聊天的对象。用户点击在线好友的昵称点击选择好友即可向该好友发送信息,发送成功之后同时要将其发送的信息以及时间信息展示在自己的窗口之中,同时也要在指定好友的窗口之中有所显示以及时间信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值