python Socket.IO 客户端,用于向 TornadIO2 服务器发送广播消息 [英] python Socket.IO client for sending broadcast messages to TornadIO2 server

查看:21
本文介绍了python Socket.IO 客户端,用于向 TornadIO2 服务器发送广播消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个实时网络应用程序.我希望能够从我的 Python 应用程序的服务器端实现发送广播消息.

I am building a realtime web application. I want to be able to send broadcast messages from the server-side implementation of my python application.

这里是设置:

我可以成功地将 socket.io 消息从客户端发送到服务器.服务器处理这些并可以发送响应.下面我将描述我是如何做到的.

I can succesfully send socket.io messages from the client to the server. The server handles these and can send a response. In the following i will describe how i did that.

首先,我们需要定义一个处理socket.io事件的Connection:

First, we need to define a Connection which handles socket.io events:

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管理自定义方法启动服务器:

Starting the server is done by a Django management custom method:

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)

很好,服务器现在可以运行了.让我们添加客户端代码:

Very well, the server runs now. Let's add the client code:

<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".

Obviously, {{ user.username }} will be replaced by the username of the currently logged in user, in this example the username is "alp".

现在,每次刷新页面时,控制台输出为:

Now, every time the page gets refreshed, the console output is:

connected
log: hello alp

因此,调用消息和发送响应是有效的.但现在是棘手的部分.

Therefore, invoking messages and sending responses works. But now comes the tricky part.

响应hello alp"只发送给socket.io消息的调用者.我想向所有连接的客户端广播一条消息,以便在新用户加入聚会时实时通知他们(例如在聊天应用程序中).

The response "hello alp" is sent only to the invoker of the socket.io message. I want to broadcast a message to all connected clients, so that they can be informed in realtime if a new user joins the party (for example in a chat application).

那么,这是我的问题:

  1. 如何向所有连接的客户端发送广播消息?

  1. How can i send a broadcast message to all connected clients?

如何向在特定频道上订阅的多个已连接客户端发送广播消息?

How can i send a broadcast message to multiple connected clients that are subscribed on a specific channel?

如何在我的 Python 代码中的任何位置(BaseConnection 类之外)发送广播消息?这是否需要某种用于 python 的 Socket.IO 客户端,还是 TornadIO2 内置的?

How can i send a broadcast message anywhere in my python code (outside of the BaseConnection class)? Would this require some sort of Socket.IO client for python or is this builtin with TornadIO2?

所有这些广播都应该以可靠的方式完成,所以我猜 websockets 是最好的选择.但我愿意接受所有好的解决方案.

All these broadcasts should be done in a reliable way, so i guess websockets are the best choice. But i am open to all good solutions.

推荐答案

我最近在类似的设置上编写了一个非常类似的应用程序,所以我确实有一些见解.

I've recently written a very similar application on a similar setup, so I do have several insights.

做您需要的正确方法是拥有一个发布-订阅后端.使用简单的 ConnectionHandler 只能做这么多.最终,处理类级别的连接集开始变得丑陋(更不用说错误了).

The proper way of doing what you need is to have a pub-sub backend. There's only so much you can do with simple ConnectionHandlers. Eventually, handling class-level sets of connections starts to get ugly (not to mention buggy).

理想情况下,您希望使用 Redis 之类的东西,以及与龙卷风的异步绑定(查看 brukva).这样您就不必费心将客户端注册到特定频道 - Redis 拥有开箱即用的所有功能.

Ideally, you'd want to use something like Redis, with async bindings to tornado (check out brukva). That way you don't have to mess with registering clients to specific channels - Redis has all that out of the box.

本质上,你有这样的东西:

Essentially, you have something like this:

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 稳定得多.

Note that I used sockjs-tornado which I found to be much more stable than socket.io.

无论如何,一旦您进行了这种设置,从任何其他客户端(例如 Django,就您而言)发送消息就像打开 Redis 连接一样简单(redis-py 是一个安全的赌注)并发布消息:

Anyway, once you have this sort of setup, sending messages from any other client (such as Django, in your case) is as easy as opening a Redis connection (redis-py is a safe bet) and publishing a message:

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-实时网络应用程序/

这篇关于python Socket.IO 客户端,用于向 TornadIO2 服务器发送广播消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆