Подтвердить что ты не робот

Python Socket.IO-клиент для отправки широковещательных сообщений на сервер TornadIO2

Я создаю веб-приложение в реальном времени. Я хочу иметь возможность отправлять широковещательные сообщения с серверной реализации моего приложения python.

Вот настройка:

  • socketio.js на стороне клиента
  • TornadIO2 сервер как сервер Socket.IO
  • python на стороне сервера (Django) li >

Я могу успешно отправлять сообщения socket.io от клиента на сервер. Сервер обрабатывает их и может отправлять ответ. Ниже я опишу, как я это сделал.

Текущая настройка и код

Во-первых, нам нужно определить Connection, которое обрабатывает события socket.io:

class BaseConnection(tornadio2.SocketConnection):
    def on_message(self, message):
        pass

    # will be run if client uses socket.emit('connect', username)
    @event
    def connect(self, username):
        # send answer to client which will be handled by socket.on('log', function)
        self.emit('log', 'hello ' + username)

Запуск сервера выполняется с помощью настраиваемого метода управления Django:

class Command(BaseCommand):
    args = ''
    help = 'Starts the TornadIO2 server for handling socket.io connections'

    def handle(self, *args, **kwargs):
        autoreload.main(self.run, args, kwargs)

    def run(self, *args, **kwargs):
        port = settings.SOCKETIO_PORT

        router = tornadio2.TornadioRouter(BaseConnection)

        application = tornado.web.Application(
            router.urls,
            socket_io_port = port
        )

        print 'Starting socket.io server on port %s' % port
        server = SocketServer(application)

Хорошо, сервер работает сейчас. Добавьте код клиента:

<script type="text/javascript">    
    var sio = io.connect('localhost:9000');

    sio.on('connect', function(data) {
        console.log('connected');
        sio.emit('connect', '{{ user.username }}');
    });

    sio.on('log', function(data) {
        console.log("log: " + data);
    });
</script>

Очевидно, что {{ user.username }} будет заменено именем пользователя текущего пользователя, в этом примере имя пользователя - "alp".

Теперь, каждый раз, когда страница обновляется, вывод консоли:

connected
log: hello alp

Таким образом, вызывается обращение к сообщениям и отправке ответов. Но теперь идет сложная часть.

Проблемы

Ответ "hello alp" отправляется только в invoker сообщения socket.io. Я хочу передать сообщение всем подключенным клиентам, чтобы они могли быть проинформированы в реальном времени, если новый пользователь присоединяется к стороне (например, в приложении чата).

Итак, вот мои вопросы:

  • Как отправить широковещательное сообщение всем подключенным клиентам?

  • Как отправить широковещательное сообщение нескольким подключенным клиентам, которые подписаны на определенный канал?

  • Как я могу отправить широковещательное сообщение в любом месте моего кода python (вне класса BaseConnection)? Будет ли это требовать своего рода Socket.IO-клиента для python или это встроено в TornadIO2?

Все эти трансляции должны быть сделаны надежным способом, поэтому я думаю, что веб-сайты - лучший выбор. Но я открыт для всех хороших решений.

4b9b3361

Ответ 1

Недавно я написал очень похожее приложение на аналогичной установке, поэтому у меня есть несколько идей.

Правильный способ делать то, что вам нужно, это иметь паб-вспомогательный сервер. Там просто так много можно сделать с помощью простых ConnectionHandler s. В конце концов, обработка наборов соединений на уровне классов начинает становиться уродливой (не говоря уже о багги).

В идеале вы хотели бы использовать что-то вроде Redis, с асинхронными привязками к торнадо (посмотрите brukva). Таким образом, вам не нужно связываться с регистрацией клиентов по определенным каналам - у Redis все это из коробки.

По существу, у вас есть что-то вроде этого:

class ConnectionHandler(SockJSConnection):
    def __init__(self, *args, **kwargs):
        super(ConnectionHandler, self).__init__(*args, **kwargs)
        self.client = brukva.Client()
        self.client.connect()
        self.client.subscribe('some_channel')

    def on_open(self, info):
        self.client.listen(self.on_chan_message)

    def on_message(self, msg):
        # this is a message broadcast from the client
        # handle it as necessary (this implementation ignores them)
        pass

    def on_chan_message(self, msg):
        # this is a message received from redis
        # send it to the client
        self.send(msg.body)

    def on_close(self):
        self.client.unsubscribe('text_stream')
        self.client.disconnect()

Обратите внимание, что я использовал sockjs-tornado, который оказался намного более стабильным, чем socket.io.

В любом случае, если у вас есть такая настройка, отправка сообщений от любого другого клиента (например, Django, в вашем случае) так же просто, как открытие соединения Redis (redis-py - безопасная ставка) и публикация сообщения:

import redis
r = redis.Redis()
r.publish('text_channel', 'oh hai!')

Этот ответ получился довольно длинным, поэтому я прошел лишнюю милю и сделал из него сообщение в блоге: http://blog.y3xz.com/blog/2012/06/08/a-modern-python-stack-for-a-real-time-web-application/

Ответ 2

Я пишу здесь, потому что это трудно написать в разделе комментариев. Вы можете просмотреть примеры для tornadoio2 в каталоге примеров, где вы можете найти реализацию чата, и:

class ChatConnection(tornadio2.conn.SocketConnection):
    # Class level variable
    participants = set()

    def on_open(self, info):
        self.send("Welcome from the server.")
        self.participants.add(self)

    def on_message(self, message):
        # Pong message back
        for p in self.participants:
            p.send(message)

Как вы видите, они реализовали участников как заданные))

Ответ 3

Если вы уже используете django, почему бы не взглянуть на gevent-socketio.