2017-06-20 3 views
0

So eine App in NodeJS ich schreibe, und meine Frage bitte Vorwort verstehen, wie mein Setup derzeit arbeitet:Socket.IO Emit aussendet an alle Clients

Ich habe Kunden, die über Socket.io Verbindung zu " Server X ", und dann verbindet sich mein" Server X "über Socket.io mit" Server Y "und sie senden alle Daten über Socket.io zurück.

Client-< ---> Server X < ---> Server Y

Clients beziehen sich auf Anwender und ihre Browser, und ich habe dann ein Knoten App sowohl läuft auf meinem Server x und y meinem Server.

Also in dem Code unten auf meinem Server X, wenn Sie Zeile 4 betrachten, funktioniert es genau so, wie es sollte. Sie sendet die Nachricht NUR an den Kunden, der sie angefordert hat.

io.on('connection', function(socket){ 

    // This works just fine. 
    socket.emit('return_login', 'Test Message'); 

    socket.on('login', function(data){ 
     // This line correctly sends the data to Server Y 
     server_y.emit('login', data); 
    }); 

    server_y.on('return_login', function(data){ 
     // This emits to all connected clients??? 
     socket.emit('return_login', data); 
    }); 

}); 

Nun mein Problem ist, wenn „Server Y“ return_login auf Server x emittiert, was ich für Server x passieren soll, den Wert von Server y emittieren zu nehmen und es nur an den ursprünglichen Client zurückzuschicken, oder Webbrowser. Aus irgendeinem Grund wird diese Leitung jedoch an ALLE verbundenen Clients gesendet.

Ich habe einen Laptop, diesen Computer und mein Handy alle dies zu testen und jedes Mal, wenn es emittiert passiert es an JEDER sendet.

Wenn jemand mir bitte dabei helfen könnte, würde ich es sehr schätzen. Wenn ich mehr Code posten möchte, lass es mich wissen.

Antwort

0

zu allen Clients senden, weil Sie einen separaten Hörer für jede Buchse für die return_login Nachricht installiert haben. Wenn sich also ein Client anmeldet und die Nachricht return_login an Ihren Server zurückgesendet wird, haben Sie für jeden einzelnen Socket, der diese Nachricht sieht, einen separaten Listener und leiten ihn an diesen Socket weiter. Auf diese Weise wird es an jede angeschlossene Buchse gesendet.

Eine Möglichkeit, das zu beheben, besteht darin, sicherzustellen, dass die Nachricht return_login nur an den Socket gesendet wird, zu dem sie gehört. Wenn Sie eine socket.id mit dieser Nachricht senden können und dieser Server diese ID als Teil der Antwort zurückgeben kann, können Sie dies überprüfen, wenn Sie die Nachricht erhalten, um sicherzustellen, dass Sie sie nur an den Socket senden, zu dem sie gehört.

Dies ist eines der Probleme mit einem reinen nachrichtenbasierten System. Sie versuchen, eine Anfrage/Antwort auszuführen, bei der nur der Anforderer die Antwort sieht, aber socket.io kein Anforderungs-/Antwort-System ist. Eine Antwort wird an alle Listener dieser bestimmten Nachricht gesendet, und da Sie für jedes einzelne Socket, das verbunden ist, einen Listener für diese Nachricht haben, sieht jedes einzelne Socket es und leitet es dann an seinen Client weiter.

also mit einer entsprechenden Änderung auf den anderen Server den id Wert Echo zurück, könnten Sie dies tun:

io.on('connection', function(socket){ 

    // This works just fine. 
    socket.emit('return_login', 'Test Message'); 

    socket.on('login', function(data){ 
     // add our id so we can identify our response back 
     data.id = socket.id; 
     server_y.emit('login', data); 
    }); 

    let fn = function(data) { 
     // check to see if this message is destined for this socket 
     if (data.id === socket.id) { 
      // make data copy with id value removed so 
      // we don't send that to the client 
      let tempData = Object.assign({}, data); 
      tempData.delete(id); 
      socket.emit('return_login', tempData); 
      // we're done with this listener so remove it 
      server_y.removeListener('return_login', fn); 
     } 
    }); 

    server_y.on('return_login', fn); 

}); 

Es mag verlockend sein, nur Ihre Zuhörer für die Nachricht return_login zu entfernen, nachdem Sie erhalten es, aber das verursacht eine Race-Bedingung, wenn zwei Clients sich gleichzeitig anmelden und beide gleichzeitig Listener haben, dann würde die erste Nachricht von beiden Listenern empfangen werden.

+0

Du hast mein Problem gelöst, bin aber immer noch verwirrt. Warum löschen Sie die Socket-ID von diesem TempData-Objekt? Sie sagten im Kommentar make Datenkopie mit ID-Wert entfernt, so dass wir das nicht an den Client senden, aber möchten Sie nicht wissen, welche Socket-ID sie sind? Außerdem habe ich die Zeile 'server_y.removeListener ('return_login', fn);' entfernt, weil es so war, dass Sie nur eine Anmeldung versuchen konnten. – flakeyjake

+0

@flakeyjake - Der Client muss die 'socket.id' der serverseitigen Verbindung nicht kennen, also dachte ich, ich würde sie entfernen, um die gleiche Datenstruktur beizubehalten, die Sie zuvor an den Client gesendet haben. Ich sehe hier keinen Grund, es an den Kunden senden zu wollen. Wenn Sie es nicht entfernen möchten, können Sie zulassen, dass es an den Client gesendet wird - kein Schaden. Ich wusste nicht, dass du dich mehr als einmal anmelden möchtest. Ja, um dies zu tun, würden Sie entweder einen neuen Listener einrichten, wenn Sie die Login-Nachricht senden oder nicht entfernen. – jfriend00

+0

@flakeyjake - Da es so aussieht, als ob Sie hier neu sein könnten, wenn Ihre Antwort zu einer Lösung für Sie führt, können Sie dies der Community anzeigen, indem Sie auf das grüne Häkchen links neben der Antwort klicken. Dadurch erhalten Sie auch einige Reputationspunkte für das richtige Vorgehen. – jfriend00

0

Ich bin mir nicht sicher über Ihren Code. Aber ich benutze normalerweise Raum, um an eine Benutzer- und Rückruffunktion des Sockels zu senden. Dies ist meine Lösung Rückruf anstelle von return_login Ereignisse

io.on('connection', function(socket){ 
 
    socket.on('login', function(data, callback){ 
 
     
 
     // Using callback instead of return_login event 
 
     server_y.emit('login', data, function(responseData){ 
 
      
 
      // put this socket to room as name = user_id 
 
      socket.join(responseData.user_id); 
 
      
 
      // return result by callback 
 
      callback(responseData) 
 
     }); 
 
    }); 
 

 
}); 
 

 
// emit to exactly user_id with return_login event if you want 
 
io.to(user_id).emit('return_login', {key: 'ok'})

+0

Ich habe versucht, etwas ähnliches, aber es war nicht genau das, was ich suche. Ich schätze die Hilfsbereitschaft aber :) – flakeyjake

Verwandte Themen