我正在编写一个围绕Python的SimpleHTTPServer的图形用户界面包装器。它看起来是这样的:

图形用户界面使用tkinter。当我点击OK按钮时,它会启动web服务器。
web服务器代码基于https://docs.python.org/3/library/http.server.html上的文章。部分原因是:
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print("serving at port", PORT)
httpd.serve_forever()到目前为止,一切都像预期的那样工作,但是当https.server_forever()函数运行时,我得到了旋转的beachball,并且我无法关闭窗口或退出。我可以强制退出,然后再试一次,这不方便。然而,服务器确实完成了它的工作。
如果我从命令行(非gui版本)运行相同的代码,我可以很容易地用ctrl-c中断它;我可以捕获它并更优雅地退出。
如何才能更礼貌地从服务器中断正在运行的服务器?
发布于 2021-09-02 18:35:42
您将需要在线程或单独的进程中运行服务器,因为web服务器和UI都需要单独的事件循环。
如果您希望服务器与tkinter程序进行通信,则需要设置一个队列。一般来说,您应该只从创建tkinter对象的线程访问tkinter对象。但是,我认为将虚拟事件从工作线程发送到GUI线程是安全的,您可以使用它使GUI线程从队列中读取数据。
例如,这是一个简单的线程化服务器。必须向其传递主机和端口、对根窗口的引用以及对队列的引用,在该队列中可以将信息发送到GUI。
class ExampleServer(threading.Thread):
def __init__(self, host, port, gui, queue):
threading.Thread.__init__(self)
self.host = host
self.port = port
self.gui = gui
self.queue = queue
self.daemon = True
def run(self):
print(f"Listening on http://{self.host}:{self.port}\n")
server = HTTPServer((self.host, self.port), ExampleHandler)
server.serve_forever()在请求处理程序中,可以将项推入队列,然后在根窗口上生成事件。它可能看起来像这样:
class ExampleHandler(BaseHTTPRequestHandler):
def do_GET(self):
# handle the request
...
# notify the UI
self.queue.put("anything you want")
self.gui.event_generate("<<DataAvailable>>")您的gui还需要将队列作为参数,并需要设置虚拟事件的绑定。它可能看起来像这样:
class ExampleGUI(tk.Tk):
def __init__(self, queue):
super().__init__()
self.queue = queue
# set up the rest of the GUI
...
# bind to the virtual event
self.bind("<<DataAvailable>>", self.poll_queue)
def poll_queue(self, event):
while not queue.empty():
data = self.queue.get_nowait()
# Do whatever you need to do with the data
...
def start(self):
self.mainloop()最后,您可以使用下面这样的代码将它们联系在一起:
if __name__ == "__main__":
queue = queue.Queue()
gui = ExampleGUI(queue)
server = ExampleServer("localhost", 8910, gui, queue)
server.start()
gui.start()https://stackoverflow.com/questions/69026448
复制相似问题