Python Autobahn从外部应用程序发送用户特定和广播消息

Python Autobahn从外部应用程序发送用户特定和广播消息,python,websocket,twisted,autobahn,Python,Websocket,Twisted,Autobahn,对WebSocket来说是全新的 我在理解如何从另一个应用程序与python Autobahn/twisted交互时遇到了一些困难,似乎找不到任何有用的示例 我有一个Python应用程序正在运行,它需要在某些事件上发送两种消息中的一种。第一种是向所有用户广播消息。第二种类型是针对单个特定用户的 使用以下两个示例,我可以接收消息并发送响应。但是,我不需要从连接的客户端(连接到websockets服务器的客户端除外)接收任何内容,只需要发送给它们即可 我玩过: 此外(与高速公路无关): 问题: 1-

对WebSocket来说是全新的

我在理解如何从另一个应用程序与python Autobahn/twisted交互时遇到了一些困难,似乎找不到任何有用的示例

我有一个Python应用程序正在运行,它需要在某些事件上发送两种消息中的一种。第一种是向所有用户广播消息。第二种类型是针对单个特定用户的

使用以下两个示例,我可以接收消息并发送响应。但是,我不需要从连接的客户端(连接到websockets服务器的客户端除外)接收任何内容,只需要发送给它们即可

我玩过:

此外(与高速公路无关):

问题:

1-我正在尝试的是可能的吗?我是否可以有一个外部应用程序与高速公路应用程序/服务器连接,并向所有连接的用户或单个用户广播消息

2-如果可能的话,有人能给我指出正确的方向来学习如何做到这一点吗


首先,Autobahn项目提供了通信协议WAMP的开源实现。 WAMP提供了两种通信模式:RPC(远程过程调用)和PUBSUB(发布-订阅)。因此,在您的情况下,有必要找出这两种模式中的哪一种适合您的需要

RPC

根据报告,RPC涉及三个角色。这些是:

  • 来电者
  • 被叫
  • 经销商
在您的例子中,被调用方是服务器,而调用方(客户端)调用服务器上的方法。这显然对你有用。(可以将返回值发送给被叫方/客户端)。经销商负责布线,目前可以忽略。因此,考虑到上述模式,它似乎不适合您的问题

PUBSUB

第二种模式是PUBSUB。此模式由三个角色组成(取自):

  • 出版者
  • 订户
  • 经纪人
因此,发布者(服务器)将事件发布到主题。订阅者(客户端)可以订阅发布者的主题。一旦发布事件,订阅者将接收包括有效负载的事件。这意味着您可以提供一个主题“广播”,并让所有客户端订阅该主题。如果需要,您可以向所有客户端发送广播消息

然后,您必须处理向单个客户端(订户)发送消息的问题。根据文档,用于发布主题的发布函数有一个可选参数,用于提供有资格接收事件的“客户端”列表

------编辑-----

目前还不清楚“外部应用程序”是什么意思以及应该用什么语言编写。如果外部应用程序是用python、JavaScript或Cpp编写的,或者是使用Autobahn framework with(WAMP)的Android应用程序,那么作者解释的问题就可以解决

正如问题中提到的,Autobahn还提供websocket协议实现。解决此问题的另一种方法是使用Autobahn Websocket,对于“外部应用程序”,可以选择Websocket实现。Autobahn提供Python和Android Websocket解决方案。当然,还有更多的Websocket库或模块可用,还有更多

假设Websocket服务器是使用Autobahn框架实现的。外部应用程序是另一个连接到服务器并发送定义字符串(以“send_broadcast:PAYLOAD”开头)和附加的有效负载的客户端。在服务器上,您可以检查消息中的字符串,如果消息以“send_broadcast”开头,则可以将广播发送到所有连接的客户端。如果只想将消息发送给一个客户机,可以定义另一个字符串,例如“send_to_single:IP:PAYLOAD”。然后,服务器实现可以有另一个elif分支来检查“send_to_single”并调用另一个方法,可能是“def send_to_single”,并根据客户端的ip传递另一个参数。您可以只向给定的客户机发送消息,而不是像广播方法那样向所有客户机发送消息。您自己的通信协议的另一种方式是使用JSON。 您可以如下定义您的msg:

{
    "type": "broadcast",
    "msg": "your_message"
}

然后在服务器上加载负载,检查类型并执行进一步的步骤

服务器

import sys

from twisted.internet import reactor
from twisted.python import log
from twisted.web.server import Site
from twisted.web.static import File

from autobahn.twisted.websocket import WebSocketServerFactory, \
    WebSocketServerProtocol, \
    listenWS


class BroadcastServerProtocol(WebSocketServerProtocol):

    def onOpen(self):
        self.factory.register(self)

    def onConnect(self, request):
        print("Client connecting: {}".format(request.peer))

    def onMessage(self, payload, isBinary):
        if not isBinary:
            if "send_broadcast" in payload.decode('utf8'):
                msg = "Send broadcast was ordered"
                self.factory.broadcast(msg)

    def connectionLost(self, reason):
        WebSocketServerProtocol.connectionLost(self, reason)
        self.factory.unregister(self)


class BroadcastServerFactory(WebSocketServerFactory):

    """
    Simple broadcast server broadcasting any message it receives to all
    currently connected clients.
    """

    def __init__(self, url, debug=False, debugCodePaths=False):
        WebSocketServerFactory.__init__(self, url, debug=debug, debugCodePaths=debugCodePaths)
        self.clients = []
        self.tickcount = 0
        self.tick()

    def tick(self):
        self.tickcount += 1
        self.broadcast("tick %d from server" % self.tickcount)
        reactor.callLater(1, self.tick)

    def register(self, client):
        if client not in self.clients:
            print("registered client {}".format(client.peer))
            self.clients.append(client)

    def unregister(self, client):
        if client in self.clients:
            print("unregistered client {}".format(client.peer))
            self.clients.remove(client)

    def broadcast(self, msg):
        print("broadcasting message '{}' ..".format(msg))
        for c in self.clients:
            c.sendMessage(msg.encode('utf8'))
            print("message sent to {}".format(c.peer))


class BroadcastPreparedServerFactory(BroadcastServerFactory):

    """
    Functionally same as above, but optimized broadcast using
    prepareMessage and sendPreparedMessage.
    """

    def broadcast(self, msg):
        print("broadcasting prepared message '{}' ..".format(msg))
        preparedMsg = self.prepareMessage(msg)
        for c in self.clients:
            c.sendPreparedMessage(preparedMsg)
            print("prepared message sent to {}".format(c.peer))


if __name__ == '__main__':

    if len(sys.argv) > 1 and sys.argv[1] == 'debug':
        log.startLogging(sys.stdout)
        debug = True
    else:
        debug = False

    ServerFactory = BroadcastServerFactory
    # ServerFactory = BroadcastPreparedServerFactory

    factory = ServerFactory("ws://localhost:9000",
                            debug=debug,
                            debugCodePaths=debug)

    factory.protocol = BroadcastServerProtocol
    factory.setProtocolOptions(allowHixie76=True)
    listenWS(factory)

    webdir = File(".")
    web = Site(webdir)
    reactor.listenTCP(8080, web)

    reactor.run()
客户端 客户机也是用Python编写的,使用了不同的模块实现,仍然可以工作。当然,有必要使用Websocket协议与Websocket服务器通信

from websocket import create_connection
ws = create_connection("ws://localhost:9000")
print "Sending 'send_broadcast'..."
ws.send("send_broadcast:PAYLOAD")
print "Sent"
print "Reeiving..."  # OPTIONAL
result = ws.recv()   # OPTIONAL
print "Received '%s'" % result    # OPTIONAL
ws.close(

)

但这个问题尚未得到回答。上面的例子没有广播来自外部源的消息,它们只是使用睡眠每5秒广播一条内部消息。因此,请解释您的外部源是什么。智能手机(IOS/Android)还是浏览器?或者一台电脑/笔记本电脑?嗯,我编辑了我的答案,给出了如何连接到服务器的提示,并要求服务器向单个客户端发送广播或消息。它不包括单客户端消息,但解释了如何管理它。问题是要指出正确的方向。我希望这个答案能帮助你知道接下来该怎么做。
from websocket import create_connection
ws = create_connection("ws://localhost:9000")
print "Sending 'send_broadcast'..."
ws.send("send_broadcast:PAYLOAD")
print "Sent"
print "Reeiving..."  # OPTIONAL
result = ws.recv()   # OPTIONAL
print "Received '%s'" % result    # OPTIONAL
ws.close(