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

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

问题描述

我正在构建一个实时的Web应用程序。 我想能够从我的python应用程序的服务器端实现发送广播消息。



这是设置:





我可以成功发送套接字。 io消息从客户端到服务器。服务器处理这些并可以发送响应。在下面我会描述我是如何做到的。



当前设置和代码



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

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

#如果客户端使用socket.emit('connect',用户名)
@event
def connect(self,username )
#发送客户端的答案将由socket.on('log',函数)处理
self.emit('log','hello'+ username)

启动服务器是由Django管理自定义方法完成的:

  class Command(BaseCommand):
args =''
help ='启动TornadIO2服务器来处理socket.io连接'

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

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

router = tornadio2.TornadioRouter(BaseConnection)

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


print'在端口%s上启动socket.io服务器%port
服务器= SocketServer(应用程序)

很好,服务器现在运行。我们添加客户端代码:

 < 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 仅发送到socket.io消息的调用者。我想向所有连接的客户端广播消息,以便如果新用户加入聚会(例如在聊天应用程序中),可以实时通知他们。



所以,这里是我的问题:


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


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


  3. 我可以在我的python代码( BaseConnection 类之外)发送广播消息吗?这是否需要某种类型的Socket.IO客户端用于python或者是内置TornadIO2?


所有这些广播应该以可靠的方式完成,所以我猜websockets是最好的选择。但是我对所有好的解决方案是开放的。

解决方案

我最近在类似的设置中写了一个非常相似的应用程序,所以我确实有几个见解。



正确的方式做你需要的是一个pub-sub后端。只需要简单的 ConnectionHandler 就可以做到这一点。最终,处理类级别的连接开始变得丑陋(更不用说越野车)。



理想情况下,您希望使用类似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('

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

def on_message(self,msg):
#这是从客户端发送的消息
#根据需要处理它(此实现忽略它们)
pass

def on_chan_message(self,msg):
#这是从redis收到的消息
#将其发送给客户端
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 /


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.

Here is the setup:

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.

Current Setup and Code

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)

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>

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.

Problems

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

So, here are my questions:

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

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

  3. 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?

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.

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

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()

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

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!')


This answer turned out pretty long, so I went the extra mile and made a blog post out of it: http://blog.y3xz.com/blog/2012/06/08/a-modern-python-stack-for-a-real-time-web-application/

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

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