对于我正在开发的 django 应用程序,我需要实现一种双向 RPC,以便:
- 客户端可以从平台调用 RPC 方法,并且
- 平台可以从每个客户端调用 RPC 方法。
由于客户端大多位于 NAT 后面(这意味着没有公共 IP 和不可预测的奇怪防火墙策略(,因此平台到客户端的方式必须由客户端启动。
我对如何从头开始编写它有一个很好的想法,我也认为我可以从 twisted 的发布者/订阅者模型中做一些事情,但我已经了解到在 python 中总有最好的方法。
所以我想知道最好的方法是什么,这也会将最好的集成到 django 中。代码必须能够在短期内与数百个客户端合作,并且(我们希望(在中/长期内与数千个客户端合作。
那么你会建议我使用什么库/实现?我主要寻找RTFM的起点!
websocket是一个移动的目标,不时有新的规范。勇敢的开发人员实现了服务器端库,但很少有人实现客户端。Web 套接字的客户端是 Web 浏览器。
WebSocket 不是服务器与客户端通信的唯一方式,事件源是将信息推送到客户端的简单实用的方式。这只是一个永无止境的页面。推特消防水带在其规范之前使用此技巧。客户端打开 http 连接并等待事件。连接保持打开状态,如果出现问题(连接中断,类似情况(,请重新打开。没有超时,您可以在一个连接中发送多个事件。
websocket 和 eventsource 之间的区别很简单。Websocket是双向的,难以实现。事件源是单向的,易于实现,无论是客户端还是服务器端。
您可以将事件源用作僵尸控制器。每个客户端连接并重新连接到主客户端并等待指令。当收到指令时,僵尸会采取行动,如果需要,可以通过经典的http连接与其主人交谈,针对django应用程序。
事件源保持连接打开,因此您需要一个异步服务器,例如龙卷风。Django 需要一个同步服务器,所以,你需要两者,以及一个调度程序,比如 nginx。Django 或类似 cron 的动作与异步服务器对话,与正确的僵尸对话。僵尸与 django 对话,所以,异步服务器不需要任何运行,它只是一个带有插入僵尸的集线器。
Gevent能够处理这样的http服务器,但是没有像样的文档和示例。太可惜了。我想要一辆车,你给我一个螺丝钉。
您也可以使用龙卷风+龙卷风+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)
这是我能想出的一个非常简单的解决方案:
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("%srn" % 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。
我最近玩过Django,Server-Sent Events和WebSocket,我在 http://curella.org/blog/2012/jul/17/django-push-using-server-sent-events-and-websocket/写了一篇关于它的文章
当然,这伴随着通常的警告,即Django可能不是最适合事件的东西,而且这两个协议仍然是草案。