【问题标题】:Websocket/event-source/... implementation to expose a two-way RPC to a python/django applicationWebsocket/event-source/... 实现向 python/django 应用程序公开双向 RPC
【发布时间】:2012-05-26 19:00:10
【问题描述】:

对于我正在开发的 django 应用程序,我需要实现两种 RPC 方式:

  • 客户端可以从平台调用 RPC 方法并
  • 平台可以从每个客户端调用 RPC 方法。

由于客户端大多位于 NAT 之后(这意味着没有公共 IP,以及不可预知的怪异防火墙策略),因此平台到客户端的方式必须由客户端发起。

我对如何从头开始编写这个有一个很好的想法,我也认为我可以从扭曲的发布者/订阅者模型中解决一些问题,但我了解到总有最好的方法来做到这一点在python中。

所以我想知道最好的方法是什么,也可以将最好的方法集成到 django。该代码必须能够在短期内覆盖数百个客户,并且(我们希望)在中/长期内覆盖数千个客户。

那么您建议我使用什么库/实现? 我主要是在寻找 RTFM 的起点!

【问题讨论】:

标签: python django websocket rpc


【解决方案1】:

我最近玩过 Django、Server-Sent Events 和 WebSocket,我在http://curella.org/blog/2012/jul/17/django-push-using-server-sent-events-and-websocket/写了一篇关于它的文章

当然,这伴随着一个常见的警告,即 Django 可能不是最适合事件处理的东西,而且这两个协议仍然是草稿。

【讨论】:

  • 有趣的文章,虽然在 wsgi 支持多线程之前,在生产中走这条路是不可想象的。
【解决方案2】:

你也可以使用 Tornado + Tornadio + Socket.io。这就是我们现在用于通知的内容,您应该编写的代码量并不多。

from tornadio2 import SocketConnection, TornadioRouter, SocketServer
class RouterConnection(SocketConnection):
__endpoints__ = {'/chat': ChatConnection,
                 '/ping': PingConnection,
                 '/notification' : NotificationConnection
                 }

def on_open(self, info):
    print 'Router', repr(info)

MyRouter = TornadioRouter(RouterConnection)

# Create socket application
application = web.Application(
MyRouter.apply_routes([(r"/", IndexHandler),
    (r"/socket.io.js", SocketIOHandler)]),
        flash_policy_port = 843,
        flash_policy_file = op.join(ROOT, 'flashpolicy.xml'),
        socket_io_port = 3001,
        template_path=os.path.join(os.path.dirname(__file__), "templates/notification")
)

class PingConnection(SocketConnection):
     def on_open(self, info):
       print 'Ping', repr(info)

     def on_message(self, message):
       now = dt.utcnow()
       message['server'] = [now.hour, now.minute, now.second, now.microsecond / 1000]
       self.send(message)
class ChatConnection(SocketConnection):
   participants = set()
   unique_id = 0

   @classmethod
   def get_username(cls):
       cls.unique_id += 1
       return 'User%d' % cls.unique_id

   def on_open(self, info):
       print 'Chat', repr(info)

       # Give user unique ID
       self.user_name = self.get_username()
       self.participants.add(self)

   def on_message(self, message):
       pass

   def on_close(self):
       self.participants.remove(self)

   def broadcast(self, msg):
       for p in self.participants:
            p.send(msg)

【讨论】:

  • 该死的...我在龙卷风中完成了完整的 event_source 实现后才看到您的评论...而且它有更多的 locs ! (虽然你的回答看起来很酷,但我没有勇气尝试另一种解决方案,而且由于我根据 athoune 的建议编写的解决方案,我会让他保留“已接受的答案”)。
  • 太糟糕了 :) 没问题。其他人也会受益。
【解决方案3】:

这是我能想到的一个非常简单的解决方案:

import tornado.ioloop
import tornado.web
import time

class MainHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous 
    def get(self):
        self.set_header("Content-Type", "text/event-stream")
        self.set_header("Cache-Control", "no-cache")
        self.write("Hello, world")
        self.flush()
        for i in range(0, 5):
            msg = "%d<br>" % i
            self.write("%s\r\n" % msg) # content
            self.flush()
            time.sleep(5)


application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

curl http://localhost:8888

当它出现时给出输出!

现在,我只需要在服务器和客户端之间实现完整的事件源规范和某种数据序列化,但这很简单。完成后,我将发布一个指向我将在此处编写的库的 URL。

【讨论】:

【解决方案4】:

websocket 是一个移动的目标,不时有新的规范。勇敢的开发者实现服务器端库,但很少实现客户端。 web socket的客户端是一个web浏览器。

websocket 不是服务器与客户端对话的唯一方式,event source 是一种将信息推送到客户端的简单实用的方式。这只是一个永无止境的页面。 Twitter 消防水带在其规范之前使用了这个技巧。客户端打开一个 http 连接并等待事件。连接保持打开状态,如果出现问题(连接断开,类似的东西),则重新打开。 没有超时,您可以在一个连接中发送多个事件。

websocket 和 eventsource 的区别很简单。 Websocket 是双向的,难以实现。 Eventsource 是单向的,并且在客户端和服务器端都易于实现。

您可以将事件源用作僵尸控制器。每个客户端连接并重新连接到主服务器并等待指令。当收到指令时,僵尸会行动,如果需要,它可以通过经典的 http 连接与它的主人交谈,目标是 django 应用程序。

Eventsource 保持连接打开,所以你需要一个异步服务器,比如 tornado。 Django 需要一个同步服务器,所以,你需要两者,还有一个调度器,比如 nginx。 Django 或类似 cron 的操作与异步服务器对话,与正确的僵尸对话。 Zombie 与 django 对话,因此,异步服务器不需要任何持久性,它只是一个插入了僵尸的集线器。

Gevent 能够处理这样的 http 服务器,但在这一点上没有像样的文档和示例。这是一个耻辱。我想要一辆车,你给我一个螺丝钉。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多