加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – 如何在Tornado中创建几个websocket聊天?

发布时间:2020-12-20 12:05:59 所属栏目:Python 来源:网络整理
导读:我正在尝试使用几个聊天创建一个Tornado应用程序.聊天应该基于 HTML5 websocket. Websockets很好地沟通,但我总是遇到每个消息被发布两次的问题. 该应用程序使用四个类来处理聊天: 聊天包含到目前为止所有已写入的消息以及包含所有应通知的服务员的列表 Chat
我正在尝试使用几个聊天创建一个Tornado应用程序.聊天应该基于 HTML5 websocket. Websockets很好地沟通,但我总是遇到每个消息被发布两次的问题.

该应用程序使用四个类来处理聊天:

>聊天包含到目前为止所有已写入的消息以及包含所有应通知的服务员的列表
> ChatPool用作新Websockets的查找 – 当没有具有所需scratch_id的人或返回现有聊天实例时,它会创建新聊天.
> ScratchHandler是所有HTTP请求的入口点 – 它解析基本模板并返回客户端的所有详细信息.
> ScratchWebSocket在数据库中查询用户信息,设置连接并通知聊天实例是否必须传播新消息.

如何防止多次发布消息?
如何使用龙卷风构建多聊天应用程序?

import uuid
import tornado.websocket
import tornado.web
import tornado.template

from site import models
from site.handler import auth_handler

class ChatPool(object):

    # contains all chats

    chats = {}

    @classmethod
    def get_or_create(cls,scratch_id):

        if scratch_id in cls.chats:
            return cls.chats[scratch_id]
        else:
            chat = Chat(scratch_id)
            cls.chats[scratch_id] = chat
            return chat


    @classmethod
    def remove_chat(cls,chat_id):

        if chat_id not in cls.chats: return
        del(cls.chats[chat_id])


class Chat(object):

    def __init__(self,scratch_id):

        self.scratch_id = scratch_id
        self.messages = []
        self.waiters = []

    def add_websocket(self,websocket):
        self.waiters.append(websocket)

    def send_updates(self,messages,sending_websocket):
        print "WAITERS",self.waiters   
        for waiter in self.waiters:
            waiter.write_message(messages)
        self.messages.append(messages)


class ScratchHandler(auth_handler.BaseHandler):

    @tornado.web.authenticated
    def get(self,scratch_id):

        chat = ChatPool.get_or_create(scratch_id)
        return self.render('scratch.html',messages=chat.messages,scratch_id=scratch_id)


class ScratchWebSocket(tornado.websocket.WebSocketHandler):

    def allow_draft76(self):
        # for iOS 5.0 Safari
        return True

    def open(self,scratch_id):

        self.scratch_id = scratch_id
        scratch = models.Scratch.objects.get(scratch_id=scratch_id)

        if not scratch:
            self.set_status(404)
            return

        self.scratch_id = scratch.scratch_id

        self.title = scratch.title
        self.description = scratch.description
        self.user = scratch.user

        self.chat = ChatPool.get_or_create(scratch_id)
        self.chat.add_websocket(self)        

    def on_close(self):
        # this is buggy - only remove the websocket from the chat.
        ChatPool.remove_chat(self.scratch_id)

    def on_message(self,message):
        print 'I got a message'
        parsed = tornado.escape.json_decode(message)
        chat = {
            "id": str(uuid.uuid4()),"body": parsed["body"],"from": self.user,}

        chat["html"] = tornado.escape.to_basestring(self.render_string("chat-message.html",message=chat))
        self.chat.send_updates(chat,self)

注意:在@A的反馈之后. Jesse我从Chat更改了send_updates方法.不幸的是,它仍然返回双倍值.

class Chat(object):

    def __init__(self,sending_websocket):

        for waiter in self.waiters:
            if waiter == sending_websocket:
                continue
            waiter.write_message(messages)

         self.messages.append(messages)

2.EDIT:我将我的代码与示例提供的演示进行了比较.在websocket示例中,通过WebSocketHandler子类和类方法将新消息传播给服务员.在我的代码中,它是由一个分离的对象完成的:

来自演示:

class ChatSocketHandler(tornado.websocket.WebSocketHandler):

    @classmethod
    def send_updates(cls,chat):
        logging.info("sending message to %d waiters",len(cls.waiters))

        for waiter in cls.waiters:
            try:
                waiter.write_message(chat)
            except:
                logging.error("Error sending message",exc_info=True)

我的应用程序使用一个对象而没有WebSocketHandler的子类

class Chat(object):

    def send_updates(self,sending_websocket):

        for waiter in self.waiters:
            if waiter == sending_websocket:
                continue
            waiter.write_message(messages)

        self.messages.append(messages)

解决方法

如果要创建基于Tornado的多聊天应用程序,我建议您使用某种消息队列来分发新消息.这样,您就可以在负载均衡器(如nginx)后面启动多个应用程序进程.否则,您将仅停留在一个进程中,因此在缩放方面受到严重限制.

我更新了我的旧Tornado聊天示例,以支持您要求的多房间聊天.看看存储库:

Tornado-Redis-Chat

Live Demo

这个简单的Tornado应用程序使用Redis Pub / Sub功能和websockets将聊天消息分发给客户端.通过简单地使用聊天室ID作为发布/订阅频道来扩展多房间功能非常容易.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读