2017-01-23 4 views
2

Ich begann ZeroMQ für IPC zu verwenden und machte einen einfachen Echo-Client/Server und ich bin überrascht über eine Sache. Hier ist der C++ - Code (mit zmq.hpp und zmq_addon.hpp).Wie behandelt ZeroMQ REQ/REP mehrere Clients?

Server:

zmq::context_t context(1); 
zmq::socket_t socket(context, ZMQ_REP); 
socket.bind("ipc:///tmp/machine-1"); 
while (1) { 
    zmq::multipart_t m; 
    m.recv(socket); 
    int i = m.poptyp<int>(); 
    i++; 
    m.addtyp<int>(i); 
    m.send(socket); 
} 

Auftraggeber:

zmq::context_t context(1); 
zmq::socket_t socket(context, ZMQ_REQ); 

socket.connect("ipc:///tmp/machine-1"); 

int i = 0; 
while (1) { 
    int save = i; 
    zmq::multipart_t m; 
    m.addtyp<int>(i); 
    m.send(socket); 
    m.recv(socket); 

    i = m.poptyp<int>(); 

    if (i != (save + 1)) 
     break; 

    if ((i % 100000) == 0) 
     std::cerr << "i : " << i<< "\n"; 
} 

I wie erwartet funktioniert. Der Client sendet eine int, der Server tut plus eins und sendet es zurück.

Jetzt die Magie, die ich nicht verstehe: Ich erkannte, dass ich den Client mehrere Male parallel ausführen kann und es funktioniert weiterhin, für jeden Client korrekt.

Der Vergleich zwischen save+1 und i ist immer in Ordnung.

Wie behandelt ZMQ das Concurrency-Problem auf der Serverseite? Woher weiß es, an welchen Kunden die Antwort zurückgeschickt werden muss?

Es diese Frage auf SO, aber es ist nicht meine Frage beantworten: ZeroMQ REQ/REP on ipc:// and concurrency

Antwort

4

Per den zeromq docs, wenn Sie REP.recv() in dem Server aufrufen wird es eine Nachricht von einem aufgereihte REQ zurückkehren (Client) Socket. Wenn mehrere Clients verbunden sind, wird eine Fair-Queue-Richtlinie verwendet, um eine auszuwählen. Wenn Sie REP.send() aufrufen, um zu antworten, sendet der REP-Socket immer die Antwort an den entsprechenden REQ-Client.

Das ist die "Magie" - der REP-Socket kümmert sich um das Senden der Antwort an den richtigen Client. Wenn der Client die Verbindung getrennt hat, wird nur die Antwortnachricht gelöscht.

Die docs kann klarer sein als meine Erklärung:

ZMQ_REP: A-Buchse vom Typ ZMQ_REP von einem Dienst verwendet werden Anfragen von empfangen und Antworten auf einen Client zu senden. Dieser Socket-Typ erlaubt nur eine alternierende Folge von zmq_recv (request) und folgenden zmq_send (reply) -Aufrufen. Jede empfangene Anfrage wird unter allen Clients in eine faire Warteschlange gestellt, und jede gesendete Antwort wird an den Client weitergeleitet, der die letzte Anforderung an ausgegeben hat. Wenn der ursprüngliche Requester nicht mehr existiert die Antwort wird stillschweigend verworfen.

+0

Ich habe nur den Leitfaden gelesen, Sie haben Recht in der Dokumentation von 'zmq_connect' ist es schön beschrieben. Der Schlüssel ist, dass eine ZMQ_REQ/ZMQ_RES-Verbindung auch ein bestimmtes recv/send-Muster benötigt. So können sie den Zugriff auf einen Socket sperren, wenn recv angerufen wird, und sie freigeben, wenn send aufgerufen wird (umgekehrt für die andere Seite) –

1

Die glib (und nicht sehr nützlich) Antwort ist, es funktioniert, weil sie es so geschrieben haben.

Längere Antwort: Was das ZMQ-Team getan hat, ist die Implementierung eines eigenen Message-Passing-Protokolls (zmtp) zusätzlich zu Stream-Verbindungen (IPC-Pipes, Sockets usw.). Neben dem Übergeben und Demarkieren von Nachrichten haben sie Funktionen in dieses Protokoll eingefügt, um verschiedene Muster wie REQ/REP, PUB/SUB, faire Warteschlangen usw. zu unterstützen. Um dies zu ermöglichen, laufen zmq-Bibliotheks-Threads alle zmtp Aktivitäten im Hintergrund, und Sie interagieren mit diesem Thread über Aufrufe an zmq_send, zmq_poll, etc. Die Verwendung von zmtp bedeutet, dass das Programm am anderen Ende eines Sockets auch sprechen muss zmtp; Nichts nützliches passiert, wenn ein Ende libzmq verwendet und das andere einfach den rohen Socket für sich selbst öffnet.

Es ist in der Tat ein sehr nützliches Stück Code.

Meiner Meinung nach ist dies definitiv der Weg zu gehen. ZMQ abstrahiert erfolgreich die Idee einer Verbindung zwischen zwei Ausführungssträngen bis zu einem Punkt, der nicht mehr wichtig ist, ob sie sich auf demselben Rechner befinden, im selben Prozess, getrennt durch eine Netzwerkverbindung usw. Das macht die Anwendungsentwicklung einfach - alles kann überall hin gehen (Ignorieren von Problemen im Zusammenhang mit Netzwerkgeschwindigkeiten und Latenzzeiten).

Ich nehme an, dass Sie sogar ein zmq-Socket an zwei verschiedene Transporte binden können, zum Beispiel sowohl ipc als auch tcp. Das ist super nützlich!

Verwandte Themen