Python Tornado中的已连接客户端列表

时间:2013-12-03 15:03:43

标签: python multithreading scope websocket tornado

我有一个Tornado WebSocket服务器在一个由线程启动的单独进程中运行。当线程通过websockets发送消息时,该线程调用我的TornadoServer的发布方法。

在一个单独的进程上运行Tornado是我发现在没有线程阻塞的情况下启动龙卷风循环的唯一方法。

在我的主题中,我通过在线程 init 方法上调用这些方法来启动龙卷风过程:

self.p = tornado_server.TornadoServer()
self.p.daemon = True
self.p.start()

在这个线程中,我有一个无限循环试图从队列中获取消息,如果它获得消息,它会调用self.p.publish(client, message)

到目前为止,非常好。

在Tornado流程中,我基本上实现了一个发布/订阅系统。当用户打开网页时,该页面会发送特定“客户”的“订阅”消息。在“on_message”回调中,我附加了一个WebSocketHandler实例的元组和用户想要订阅全局列表的客户端。

然后,发布方法应该在列表中搜索消息的目标客户端的订阅用户,它应该调用存储在该列表上的WebSocket上的write_message。

唯一不起作用的是我的“客户”列表有不同的范围或什么。

这是我的tornado_server文件的代码:

#!/usr/bin/python2
import tornado.web, tornado.websocket, tornado.ioloop, multiprocessing

clients = []

class TornadoServer(multiprocessing.Process):

    class WebSocketHandler(tornado.websocket.WebSocketHandler):
        def on_message(self, message):
            global clients
            print 'TORNADO - Received message:', str(message)
            channel, subtopic = message.split('/')
            print 'TORNADO - Subscribing:', str(subtopic)
            clients.append((self, subtopic))

        def on_close(self):
            global clients
            for websocket, client in clients:
                if self == websocket:
                    print 'TORNADO - Removed client'
                    to_remove = (self, client)
                    clients.remove(to_remove)

    def __init__(self):
        multiprocessing.Process.__init__(self)
        self.application = tornado.web.Application([(r"/tri-anim", WebSocketHandler)])
        self.application.listen(1339)

    def run(self):
        tornado.ioloop.IOLoop.current().start()

    def publish(self, client, message):
        global clients
        for websocket, websocketclient in clients:
            if websocketclient == client:
                websocket.write_message(str(message))

无论我做什么,客户都有不同的范围。调用publish时,“clients”始终为空。有没有办法让这个工作?

1 个答案:

答案 0 :(得分:0)

您正在父进程中调用publish,但客户端列表仅在子进程中更新。使用多处理时,每个进程都会获得所有变量的副本。如果您使用线程而不是变量将被共享,但即使这样,您也需要使用IOLoop.instance()。add_callback在线程调用发布和write_message函数之间进行线程安全切换(必须在IOLoop线程)。