2015-04-29 12 views
12

Totalmente nuovo alle websocket.Autobahn che invia messaggi specifici dell'utente e trasmessi da un'applicazione esterna

Sto avendo un po 'di problemi a capire come interagire con Python Autobahn/twistato da un'altra applicazione e non riesco a trovare alcun utile esempio.

Possiedo un'applicazione Python in esecuzione su determinati eventi per l'invio di uno dei due tipi di messaggi. Il primo è un messaggio broadcast per tutti gli utenti. Il secondo tipo è per un singolo utente specifico.

Utilizzando i due esempi seguenti, è possibile ricevere messaggi e inviare una risposta. Tuttavia non ho bisogno di ricevere nulla dai client connessi (diversi dai client che si connettono al server websockets) solo per inviarli.

Ho giocato con: https://github.com/tavendo/AutobahnPython/tree/master/examples/twisted/websocket/echo

anche (non Autobahn legati): https://github.com/opiate/SimpleWebSocketServer

Domande:

1 - è quello che sto cercando di fare possibile? Posso avere un'applicazione esterna che si connetta con l'applicazione/server Autobahn e trasmetta messaggi a tutti gli utenti connessi oa un singolo utente.

2 - Se possibile qualcuno può indicarmi la giusta direzione per sapere come farlo?

Grazie

risposta

6

Prima di tutto il progetto di autostrada offre un'implementazione open source del protocollo di comunicazione WAMP. WAMP offre i due pattern di comunicazione RPC (Remote-Procedure-Call) e PUBSUB (Pubblica sottoscrizione). Quindi nel tuo caso è necessario capire quale dei due modelli si adatta alle tue esigenze.

RPC

Secondo la WAMP FAQ RPC RPC coinvolge tre ruoli. Questi sono:

  • chiamante
  • Callee
  • rivenditore

Nel tuo caso, il chiamato è il server mentre il chiamante (Client) chiama un metodo sul server. Questo è ciò che apparentemente funziona per te. (Un valore di ritorno può essere inviato a Callee/client). Il rivenditore è responsabile per il routing e può essere ignorato al momento. Quindi, considerando lo schema di cui sopra, non sembra appropriato per il tuo problema.

PubSub

Il secondo modello è PubSub.Questo modello si compone di tre ruoli (tratti da WAMP FAQ PUBSUB):

  • Editore
  • Subscriber
  • Broker

Che cosa succede è che l'editore (Server) pubblica gli eventi ad argomenti. Un Sottoscrittore (Cliente) può iscriversi a un argomento del Publisher. Una volta pubblicato un evento, il Sottoscrittore riceve l'evento incluso il carico utile. Ciò significa che potresti offrire un argomento "Broadcast" e consentire a tutti i clienti di iscriversi all'argomento. Se necessario, è possibile inviare un messaggio di trasmissione a tutti i client.

Quindi si deve affrontare il problema di inviare un messaggio a singoli client (Sottoscrittori). Secondo la documentazione, la funzione di pubblicazione per la pubblicazione di un argomento ha un parametro facoltativo per fornire un elenco di "Clienti" idonei a ricevere l'evento. WAMP Documentation (Class Publish)

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

Non è chiaro che cosa si intende per "l'applicazione esterna" e in che lingua si suppone di essere scritto. Il problema spiegato dall'autore può essere risolto se l'applicazione esterna è scritta in python, JavaScript o Cpp o un'app Android utilizzando il framework Autobahn con (WAMP).

L'autostrada offre, come indicato nella domanda, anche un'implementazione del protocollo web-socket. Un altro approccio per risolvere il problema potrebbe essere l'utilizzo di Websockets di Autobahn e, per l'applicazione esterna, l'implementazione di Websocket. Offerte di Autobahn per soluzioni Python e Android Websocket. Naturalmente ci sono più librerie o moduli Websocket disponibili. Java Websocket library, Python Websocket Client module e altro ...

Quindi diciamo che il server Websocket è implementato utilizzando il framework Autobahn. L'applicazione esterna è un altro client che si connette al server e invia una stringa definita che inizia con "send_broadcast: PAYLOAD" e il payload aggiunto. Sul server è possibile controllare il messaggio per la stringa e se il msg inizia con "send_broadcast" è possibile quindi inviare la trasmissione a tutti i client connessi. Se si desidera inviare il messaggio a un solo client, è possibile definire un'altra stringa come "send_to_single: IP: PAYLOAD", ad esempio. L'implementazione del server potrebbe quindi avere un altro ramo elif che controlla "send_to_single" e chiama un altro metodo, forse "def send_to_single"? E passa un altro argomento dato l'ip del client. Invece di inviare a tutti i client, come nel metodo di trasmissione, è possibile inviare il messaggio solo al client specificato. Un altro modo per il proprio protocollo di comunicazione sarebbe utilizzare JSON. si potrebbe definire il msg come segue:

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

o

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

sul server che si quindi caricare il Payload, controllare il tipo e fare gli ulteriori passi.

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 Il client è scritto così in Python utilizzando un diversa implementazione del modulo e funziona ancora.Ovviamente è necessario comunicare con un server Websocket utilizzando il protocollo 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(

)

+0

La questione non è stata data risposta però. L'esempio sopra non trasmette messaggi da una fonte esterna, semplicemente usano un modo di sospensione per trasmettere un messaggio interno ogni 5 secondi. – someuser

+0

Quindi, spiega per favore qual è la tua fonte esterna. Uno smartphone (IOS/Android) o un browser? O un computer/laptop? – Ben

+0

Bene, ho modificato la mia risposta, dando un suggerimento su come connettermi al server e chiedere al server di inviare una trasmissione o un messaggio a un singolo client. Non include il messaggio del singolo client, ma spiega come potrebbe essere gestito. La domanda era di indicare nella giusta direzione. Spero che la risposta aiuti a sapere da dove andare. – Ben