需要帮助理解Python中的Comet(与Django一起使用)
我花了整整两天的时间,还是搞不懂Python中Comet的各种选择和配置。我看了这里所有的回答,还找了很多博客文章。现在我感觉快要崩溃了,所以如果这个问题有什么不对的地方,我深表歉意。
我对这一切都是全新的,之前做的只是一些简单的非实时网站,后端用的是PHP或Django,服务器是Apache。
我的目标是创建一个实时聊天应用,希望能和Django结合,用于用户管理、身份验证、模板等。
每次我读到一个工具时,它总是说我还需要在它之上再加一个工具,感觉这是一条永无止境的链子。
首先,有人能把完成这个工作的所有工具分类吗?
我读到了不同的服务器、网络库、引擎、客户端的JavaScript,还有其他的东西,我完全不知道该从哪里入手。我从没想过会这么复杂。
Twisted / Twisted Web似乎很受欢迎,但我不知道怎么把它整合进来,或者还需要什么(我猜至少需要客户端的JS)。
如果我理解得没错的话,Orbited是基于Twisted构建的,那我还需要其他的东西吗?
Gevent和Eventlet跟Twisted是同一类工具吗?我还需要搭配它们使用什么其他的东西吗?
像Celery、RabbitMQ或者像Redis这样的键值存储在这个过程中扮演什么角色?我对消息队列的概念不是很理解。它们是必需的吗?提供什么服务?
有没有完整的聊天应用教程可以参考一下?
如果有人能帮我突破这个心理障碍,我会非常感激。如果我遗漏了什么,请随时问我。我知道这个问题比较复杂。
3 个回答
Redis 是一个持久化存储层,它还支持原生的 发布/订阅 功能。这意味着你不需要一直去数据库里查询新消息,而是可以订阅一个频道,消息会自动推送给你。
我找到一个 可以运行的例子,展示了你描述的系统。关键的部分在于 socketio 视图:
def socketio(request):
"""The socket.io view."""
io = request.environ['socketio']
redis_sub = redis_client().pubsub()
user = username(request.user)
# Subscribe to incoming pubsub messages from redis.
def subscriber(io):
redis_sub.subscribe(room_channel())
redis_client().publish(room_channel(), user + ' connected.')
while io.connected():
for message in redis_sub.listen():
if message['type'] == 'message':
io.send(message['data'])
greenlet = Greenlet.spawn(subscriber, io)
# Listen to incoming messages from client.
while io.connected():
message = io.recv()
if message:
redis_client().publish(room_channel(), user + ': ' + message[0])
# Disconnected. Publish disconnect message and kill subscriber greenlet.
redis_client().publish(room_channel(), user + ' disconnected')
greenlet.throw(Greenlet.GreenletExit)
return HttpResponse()
我们一步一步来看这个视图:
- 设置 socket.io,获取一个 Redis 客户端和当前用户。
- 使用 Gevent 注册一个“订阅者”——这个订阅者会接收来自 Redis 的消息,并把它们转发给客户端浏览器。
- 运行一个“发布者”,它会从 socket.io(用户的浏览器)接收消息,并把这些消息推送到 Redis。
- 重复以上步骤,直到 socket 断开连接。
Redis Cookbook 提供了关于 Redis 的 更多细节,还讨论了如何持久化消息。
关于你问题的其他部分:Twisted 是一个基于事件的网络库,可以看作是这个应用中 Gevent 的替代品。它功能强大,但根据我的经验,调试起来比较困难。
Celery 是一个“分布式任务队列”——简单来说,它可以让你把工作分散到多台机器上。这里的“分布式”意味着机器之间需要某种传输方式。Celery 支持多种传输方式,包括 RabbitMQ(还有 Redis)。
在你的例子中,只有在你需要对每条消息进行一些耗时处理,比如扫描脏话之类的情况下,Celery 才合适。即便如此,还是需要有代码来监听 socket.io 的回调,以便启动 Celery 任务。
(如果你还没完全糊涂,Celery 本身可以使用 Gevent 作为其底层的并发库。)
希望这些信息对你有帮助!
我理解你的感受,这几个月我也经历了类似的研究。虽然我还没时间去处理正式的文档,但我有一个使用Django和socket.io以及tornadio的工作示例,地址在http://bitbucket.org/virtualcommons/vcweb。我原本希望能通过队列实现Django服务器和tornadio服务器之间的直接通信(也就是说,Django视图中的逻辑将消息推送到队列,然后由tornadio处理,再将这个消息的json编码版本推送给所有感兴趣的订阅者),但这部分我还没完全实现。目前我设置的方式包括:
- 一个外部的tornado(tornadio)服务器,它在另一个端口上运行,接受socket.io请求,并与Django模型一起工作。这个服务器进程对数据库的唯一写入是需要存储的聊天消息。它可以完全访问所有Django模型等,所有实时交互都需要直接通过这个服务器进程进行。
- 需要实时访问的Django模板页面包含socket.io的JavaScript,并与tornadio服务器建立直接连接。
我也研究过orbited、hookbox和gevent,但最终选择了socket.io + tornado,因为这让我觉得可以写出最干净的JavaScript + Python代码。不过,我可能错了,因为我只是去年开始学习Python/Django的。
你可以使用 Socket.IO。它有适配器可以和 gevent 和 tornado 一起使用。你可以看看我写的关于在 Django 中使用 gevent-socketio 的博客文章,链接在这里: http://codysoyland.com/2011/feb/6/evented-django-part-one-socketio-and-gevent/