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(
)
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
Quindi, spiega per favore qual è la tua fonte esterna. Uno smartphone (IOS/Android) o un browser? O un computer/laptop? – Ben
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