高速公路从外部应用程序发送用户特定和广播消息

2024-10-04 03:15:46 发布

您现在位置:Python中文网/ 问答频道 /正文

对websockets来说是全新的。在

我在理解如何与来自另一个应用程序的pythonautobahn/twisted交互时有点困难,似乎找不到任何有用的示例。在

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

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

我玩过:https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/echo

另外(与高速公路无关):https://github.com/opiate/SimpleWebSocketServer

问题:

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

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

谢谢


Tags: 用户httpsgithub服务器com应用程序消息客户端
1条回答
网友
1楼 · 发布于 2024-10-04 03:15:46

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

RPC

根据WAMP FAQ RPC,RPC涉及三个角色。这些是:

  • 呼叫者
  • 被叫人
  • 经销商

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

PUBSUB

第二种模式是PUBSUB。此模式包含三个角色(取自WAMP FAQ PUBSUB):

  • 出版商
  • 认购人
  • 经纪人

所以发生的是,发布者(服务器)将事件发布到主题。订阅者(客户机)可以订阅发布者的主题。一旦一个事件被发布,订阅者就会收到包括有效载荷在内的事件。这意味着您可以提供一个主题“广播”,并让所有客户端订阅该主题。如果需要,您可以向所有客户端发送广播消息。在

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

编辑

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

正如问题中提到的,高速公路还提供了一个websocket协议实现。另一种解决问题的方法是使用高速公路Websockets,并为“外部应用程序”选择Websocket实现。Autobahn提供Python和Android Websocket解决方案。当然,还有更多的Websocket库或模块可用。Java Websocket libraryPython Websocket Client module等。。。在

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

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

或者

^{pr2}$

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

服务器

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(

相关问题 更多 >