3

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

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

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

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

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

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

4

4 回答 4

7

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

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

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

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

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

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

于 2012-05-23T16:55:29.523 回答
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)
于 2012-05-23T22:05:48.593 回答
1

这是我可以想出的一个非常简单的解决方案:

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。

于 2012-05-23T17:46:30.137 回答
1

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

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

于 2012-07-18T16:22:51.150 回答