Autobahn sending user specific and broadcast messages from external application

前端 未结 1 1403
既然无缘
既然无缘 2021-02-19 11:14

Totally new to websockets.

I am having a bit of trouble understanding how to interact with python Autobahn / twisted from another application and cannot seem to find any

1条回答
  •  [愿得一人]
    2021-02-19 11:51

    First of all the Autobahn project offers an Open-Source implementation of the communication protocol WAMP. WAMP offers the two communication pattern RPC (Remote-Procedure-Call) and PUBSUB (Publish-Subscribe). So in your case it is necessary to figure out which of the two pattern fits your needs.

    RPC

    According to the WAMP FAQ RPC the RPC involves three Roles. These are:

    • Caller
    • Callee
    • Dealer

    In your case, the Callee is the server whereas the Caller (Client) calls a method on the server. This is what apparently works for you. (A return value can be send to the Callee/client). The dealer is responsible for the routing and can be ignored at the moment. So considering the above pattern it seems to be not fitting for your problem.

    PUBSUB

    The second pattern is PUBSUB. This pattern consists of the three roles (taken from WAMP FAQ PUBSUB):

    • Publisher
    • Subscriber
    • Broker

    So what happens is, that the Publisher (Server) publishes events to topics. A Subscriber (Client) can subscribe to a topic of the Publisher. Once an event is published the Subscriber receives the event including the payload. That means that you could offer a topic "Broadcast" and let all clients subscribe to the topic. If required you can send a broadcast message to all clients.

    Then you have to deal with the problem of sending a message to single clients (Subscribers). According to the documentation, the publish function for publishing a topic has an optional parameter to give a list of "Clients" that are eligible to receive the event. WAMP Documentation (Class Publish)

    --------EDIT--------

    It is not clear what is meant by the "external application" and in what language it is supposed to be written. The explained problem by the Author can be solved if the external application is either written in python, JavaScript or Cpp or an Android App using the Autobahn framework with (WAMP).

    Autobahn offers, as mentioned in the question, also a websocket protocol implementation. Another approach to solve the problem could be by using Autobahn Websockets and for the "external Application" a Websocket implementation of choice. Autobahn offers for Python and Android Websocket solutions. Of course there are more Websocket libraries or modules available. Java Websocket library, Python Websocket Client module and more...

    So lets say the Websocket Server is implemented using the Autobahn framework. The external application is another client connecting to the server and sending a defined string starting with "send_broadcast:PAYLOAD" and the payload appended. On the server you could check the message for the string and if the msg starts with "send_broadcast" you can then send the broadcast to all connected clients. If you want to send the msg to just one client you can define another string like "send_to_single:IP:PAYLOAD" for example. The server implementation could then have another elif branch that checks for the "send_to_single" and call another method, maybe "def send_to_single"?, and pass another argument given the ip of the client. Instead of sending to all clients ,as in the broadcast method, you could send the msg only to the given client. Another way for your own communication protocol would be using JSON. you could define your msg as follows:

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

    or

    {
        "type": "single",
        "elegible": ["IP_1", "???"],
        "msg": "your_message"
    }
    

    On the Server you then load the Payload, check the type and do the further steps.

    Server

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

    Client The client is written as well in Python using a different module implementation and still works. It is of course neccessary to comunicate with a Websocket Server using the Websocket protocol.

    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(
    

    )

    0 讨论(0)
提交回复
热议问题