带有GUI的ThreadedHTTPServer在python

时间:2015-09-19 07:52:59

标签: python multithreading user-interface webserver

我正在用Python编写一个简单的程序。我希望RequestHandler的类和GUI类同时在单独的线程中运行,并且在RequestHandler中生成的消息经常在GUI中显示(在每个post请求中将生成一个或两个消息)。这是我的代码的简化版本:

import web
import io,json
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
urls = ('/', 'RequestHandler')

from time import sleep
import threading
from Tkinter import *

serialdata = []
data = True
msguser = ''

class RequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
       length = int(self.headers['Content-length'])
       mylogs=self.rfile.readline(length)
       val= json.loads(mylogs)
       if val['RunningApp'].find('viber') >= 0:          
            msguser = 'viber is running on Devise ID:',val['DeviceID'],'in time:',val['timestamp']
            serialdata.append(msguser)
       if val['RunningApp'].find('telegram.messenger') >= 0:
            msguser = 'Telegram is running on Devise ID:',val['DeviceID'],'in time:',val['timestamp']
            serialdata.append(msguser)

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    pass

class Gui(object):
    def __init__(self):
        self.root = Tk()
        self.lbl = Label(self.root, text="")
        self.updateGUI()
        self.readSensor()

    def run(self):
        self.lbl.pack()
        self.lbl.after(1000, self.updateGUI)
        self.root.mainloop()

    def updateGUI(self):
        msg = "Data is True" if data else "Data is False"
        self.lbl["text"] = msg
        self.root.update()
        self.lbl.after(1000, self.updateGUI)

    def readSensor(self):
        self.lbl["text"] = serialdata[-1]
        self.root.update()
        self.root.after(527, self.readSensor)

if __name__ == "__main__":
    server = ThreadedHTTPServer(('X.X.X.X', 1024), RequestHandler)
    print 'Starting server, use <Ctrl-C> to stop'
    Gui().run()
    server.serve_forever()

当我运行它时,我收到错误:self.lbl["text"] = serialdata[-1] IndexError: list index out of range 当我给self.lbl["text"]一个静态字符串时,例如“收到新事件”

程序不能作为多线程运行,并且在GUI运行之前do_post永远不会运行和工作。

1 个答案:

答案 0 :(得分:0)

你必须在它自己的线程中运行服务器:

def main():
    server = ThreadedHTTPServer(('X.X.X.X', 1024), RequestHandler)
    print 'Starting server, use <Ctrl-C> to stop'
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.start()
    Gui().run()
    server.shutdown()

if __name__ == "__main__":
    main()

开头serialdata为空,因此访问serialdata[-1]失败。如果数据可用,请检查:

def readSensor(self):
    if serialdata:
        self.lbl["text"] = serialdata.pop()
    self.root.after(527, self.readSensor)

更好的是,使用队列进行通信:

import threading
import json
from Queue import Queue, Empty
from SocketServer import ThreadingMixIn
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
import Tkinter as tk

class RequestHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        length = int(self.headers['Content-length'])
        mylogs = self.rfile.read(length)
        val = json.loads(mylogs)
        if 'viber' in val['RunningApp']:
            app = 'viber'
        if 'telegram.messenger' in val['RunningApp']:
            app = 'Telegram'
        self.server.queue.put('%s is running on Devise ID: %s in time: %s' % (app, val['DeviceID'], val['timestamp']))

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    pass

class Gui(object):
    def __init__(self, root, queue):
        self.queue = queue
        self.lbl = tk.Label(root, text="")
        self.lbl.pack()
        self.read_sensor()

    def read_sensor(self):
        try:
            self.lbl["text"] = self.queue.get_nowait()
        except Empty:
            pass
        self.lbl.after(527, self.readSensor)

def main():
    server = ThreadedHTTPServer(('X.X.X.X', 1024), RequestHandler)
    server.queue = Queue()
    print 'Starting server, use <Ctrl-C> to stop'
    server_thread = threading.Thread(target=server.serve_forever)
    server_thread.start()
    root = tk.Tk()
    gui = Gui(root, server.queue)
    root.mainloop()
    server.shutdown()

if __name__ == "__main__":
    main()