2012-11-16 18 views
10

ich Nachrichten vom Server auf WebSockets senden und empfangen kann. Ich brauche eine Funktion zu schreiben, die Daten an den Server senden und eine Antwort vom Server wartet und dann wieder als Ergebnis einer Funktion.Synchron-Anfrage mit Websockets

Senden:

ws.send('my_message_to_server'); 

Receive (es ist ein Ereignis):

ws.bind('message', function(message) { 
console.log(message); 
}); 

Meine Funktion:

function request(message){ 
ws.send(message); 
    //How wait for receive??? 
    return response; 
} 
+0

Sie können eine synchrone Funktion für etwas asynchrones nicht machen. Beschäftigtes Warten ist yuck, und JavaScript unterstützt es nicht. Warum möchtest du das tun? Schauen Sie sich Versprechungen an. – Bergi

+0

@Bergi eigentlich kannst du. werfen Sie einen Blick auf meine Antwort unten. Erstellen Sie einfach eine einfache Warteschlange, in diesem Beispiel wartet kein Warten :) –

+0

@RonanDejhero: Nein, Ihre Funktion ist nicht synchron. Es verwendet einen asynchronen Callback, wie es jeder Socket-Listener benötigt. – Bergi

Antwort

3

Wenn Sie eine websocket erstellen, müssen Sie in der Regel eine onmessage Callback-Funktion hinzufügen an den Socket, der immer dann aufgerufen wird, wenn der Client Daten vom Server empfängt.

var socket = new WebSocket("ws://example.com:8000/websocketapp.php"); 
socket.onmessage = function(msg){ 
     alert('The server says: ' + msg); 
} 

Eine Funktion, die blockiert, bis der Server konzeptionell eine schlechte Idee reagiert, weil es bedeutet, dass die Ausführung des Skripts vom Server, bis die Antwort hereinkam hängen wird. Wenn der Server ausgelastet ist und die Netzwerklatenz ist hoch Dies kann einige Sekunden dauern. Aus diesem Grund ist es besser, mit Callback-Funktionen zu arbeiten (Funktionen, die aufgerufen werden, wenn ein Ereignis eintritt).

Wenn Sie garantieren können, dass Sie nur eine Anfrage zu einem Zeitpunkt an den Server senden, können Sie einfach die socket.onmessage Funktion auf eine Funktion ändern, die die Server-Antwort verarbeitet und wirkt auf sie:

socket.onopen = function() { 
    socket.send("What's your name?"); 
    socket.onmessage = function(message) { 
     alert("The server says its name is " + message); 
     socket.send("What is the answer to life, the universe and everything?"); 
     socket.onmessage = function(msg){ 
      alert("The server says the answer is: " + msg); 
     } 
    } 
} 

(Übrigens: ich habe die Anforderung, bevor sie die Antwort-Handler für eine bessere Lesbarkeit schrieb es wäre besser, es anders zu tun, um:.. stellen sie die Antwort-Handler zuerst und dann die Anfrage senden Dies ist wichtig für den unwahrscheinlichen, aber nicht unmöglich Fall, dass der Server so schnell reagiert, dass der Handler noch nicht eingerichtet wurde).

Aber wenn man mehrere parallele Anfragen haben, und Sie müssen herausfinden, die der Server anfordern bezieht sich auf, werden Sie etwas besser brauchen. Sie könnten zum Beispiel eine On-Message-Funktion haben, die die Nachricht identifiziert und dann jede Nachricht an eine spezialisierte Nachrichten-Handler-Funktion weiterleitet.

+0

Du meinst wahrscheinlich 'socket.send()'? – Christoph

+0

Ja, das tue ich. Danke, ich habe diesen Fehler korrigiert. – Philipp

+0

Was ist, wenn der Server einige Informationen zurück an den Client "Pusht", wenn etwas auf der Serverseite passiert? Wie funktioniert dieser Code? es wird nicht! –

2

Sie sollten eine Art von RPC-Protokoll oben auf WebSockets verwenden. Ich schlage vor, Sie einen Blick auf WAMP nehmen, die ein WebSocket Sub-Protokoll ist die RPC und PUB/SUB Semantik ergänzt. Es enthält eine Client-Bibliothek, die die asynchrone Verbindung zu einem gewissen Grad abstrahiert, indem sie Ihnen eine auf Versprechen basierende API gibt. Hier

ein Beispiel:

var wsuri = "ws://localhost:9000"; 

ab.connect(wsuri, function (session) { 
    session.call("http://example.com/simple/calc#add", 23, 7).then(
     function (res) { 
      console.log("got result: " + res); 
     }, 
     function (error, desc) { 
      console.log("error: " + desc); 
     } 
    ); 
}); 

Es gibt eine Reihe von serverseitige Implementierungen für diese.

1

WebSocket ist wie TCP, es ist nur eine Transportschicht. Was Sie brauchen, ist ein Protokoll über webSocket laufen zu lassen. Das Protokoll sorgt für die Erstellung der Korrelationen zwischen Nachrichten für Sie. Vielleicht möchten Sie sich AMQP anschauen, das umfangreichste und vollständigste offene Protokoll für asynchrones Echtzeit-Messaging. Beispiel: https://github.com/dansimpson/amqp-js für eine einfache AMQP-Client-JS-Bibliothek.

Ich weiß nicht, welche Art von Server Sie verwenden, aber AMQP gibt Ihnen die größte Flexibilität, da es viele AMQP-Unterstützung für viele Plattformen gibt. Es gibt auch einfache AMQP Message Broker-Implementierungen. Wenn Ihr Server Java ist, sollten Sie sich JMS ansehen. In diesem Fall benötigen Sie einen aufwendigeren, aber robusten JMS-Broker.

9

Es gibt eine nette Methode, die ich vor einiger Zeit in einem Online-Spiel verwendet habe, aber Sie müssen Sachen auch auf der Serverseite ändern!

1. eine Funktion macht die Daten

var socketQueueId = 0; 
var socketQueue = {}; 

function sendData(data, onReturnFunction){ 
    socketQueueId++; 
    if (typeof(returnFunc) == 'function'){ 
     // the 'i_' prefix is a good way to force string indices, believe me you'll want that in case your server side doesn't care and mixes both like PHP might do 
     socketQueue['i_'+socketQueueId] = onReturnFunction; 
    } 
    jsonData = JSON.stringify({'cmd_id':socketQueueId, 'json_data':data}); 
    try{ 
     webSocket.send(jsonData); 
     console.log('Sent'); 
    }catch(e){ 
     console.log('Sending failed ... .disconnected failed'); 
    } 
} 

Dann in der Server-Seite zu senden, wenn die Anfrage ist, sollten Sie die cmd_id zurück an den Client mit der Antwort

webSocket.onmessage = function(e) { 

    try{ 
     data = JSON.parse(e.data); 
    }catch(er){ 
     console.log('socket parse error: '+e.data); 
    } 

    if (typeof(data['cmd_id']) != 'undefined' && typeof(socketQueue['i_'+data['cmd_id']]) == 'function'){ 
     execFunc = socketQueue['i_'+data['cmd_id']]; 
     execFunc(data['result']); 
     delete socketQueue['i_'+data['cmd_id']]; // to free up memory.. and it is IMPORTANT thanks Le Droid for the reminder 
     return; 
    }else{ 
     socketRecieveData(e.data); 
    } 
} 

senden und Erstellen Sie eine Funktion, um alle anderen Arten von Rücksendungen zu behandeln:

socketRecieveData(data){ 
    //whatever processing you might need 
} 

so jetzt simp ly, wenn Sie einige Daten für den Server senden möchten und warten auf Antwort für diese spezifischen Daten, die Sie einfach tun:

sendData('man whats 1+1', function(data){console.log('server response:');console.log(data);}); 
+0

Wow, wirklich eine gute Idee! Es dauerte einige Zeit zu verstehen, aber das Senden des Rückrufs an den Server und jsonify es zurück zum Client ist brillant. – Benvorth

+1

Ich suchte nach dieser genauen Lösung, die zu faul ist, das Rad neu zu erfinden. Sehr elegant und flexibel. 'i_' ist optional, da Wörterbücher auch mit int funktionieren. Sie können nach dem Aufruf von execFunc Folgendes hinzufügen, um Speicherplatz freizugeben: delete socketQueue ['i _' + data ['cmd_id']]; –