2013-01-22 14 views
11

Ich baue ein kleines System, das viele Teile enthält und ich möchte eine Nachricht Pub/Sub-Dienst für die Kommunikation zwischen Teilen verwenden.Benötigen Sie einen leichten Pubsub Service/Bibliothek

Ich lese über einige Nachrichtenwarteschlangen wie RabbitMQ und ZeroMQ, aber ich fühle, dass sie zu kompliziert sind und das Gefühl haben, für verteilte Systeme geboren zu sein. Alle Teile meines Systems werden in C++/Linux geschrieben und auf eine kleine Raspberry Pi CPU gelegt, also brauche ich keine skalierbaren, plattformübergreifenden, anderen Sprachclients ...

Können Sie mir einige Ratschläge geben? über Dienstleistungen oder Bibliotheken, die meinen Bedürfnissen entsprechen? Oder du

Danke.

+0

Benötigen Sie eine Lib oder einen Dienst? Oder könnten Sie, unter den Voraussetzungen, nur Steckdosen oder Rohre verwenden? Das wäre wahrscheinlich effizienter für eine Himbeere. –

+1

ZeroMQ ist sehr einfach zu bedienen. – Kimi

+1

@ dema80: Ich bevorzuge Service, aber lib ist in Ordnung. Können Sie Steckdosen für Geräte verwenden? – Yoshi

Antwort

7

Es ist nicht so schwer, sich selbst zu tun.

Zuerst müssen Sie das zu verwendende Protokoll definieren. Es kann sehr einfach sein; wie nur ein Nachrichtentypfeld, ein Nutzlastgrößenfeld und die tatsächliche Nutzlast. Die Nachrichtentypen, die Sie benötigen, sind SUBSCRIBE, UNSUBSCRIBE und PUBLISH. Die Payload für die Nachrichten SUBSCRIBE und UNSUBSCRIBE ist der Name eines Channels zum Abonnieren/Abbestellen. Die Payload für die PUBLISH Nachricht ist der Kanalname und die tatsächlichen Daten (natürlich zusammen mit der Größe der Daten).

Um alle Teilnehmer zu verbinden, benötigen Sie einen zentralen Server. Alle Abonnenten/Publisher müssen eine Verbindung zu diesem Server herstellen. Das Serverprogramm führt eine Sammlung von Warteschlangen, eine für jeden Kanal. Wenn eine Subskribierungs- oder Veröffentlichungsnachricht für einen Kanal, der nicht existiert, beim Server eintrifft, erstellen Sie eine neue Nachrichtenwarteschlange für diesen Kanal. Für jeden Kanal benötigt der Server auch eine Sammlung aller Clients, die diesen Kanal abonniert haben. Wenn eine Veröffentlichungsnachricht beim Server ankommt, wird sie am Ende der Warteschlange für den betreffenden Kanal hinzugefügt. Während eine Kanalwarteschlange nicht leer ist, senden Sie eine Kopie davon an alle Abonnenten für diesen Kanal, und wenn alle diese empfangen haben, kann die Nachricht aus der Warteschlange entfernt werden.

Der harte Teil des Servers wird wahrscheinlich der Kommunikationsteil sein. Der einfache Teil werden alle Warteschlangen und Sammlungen, wie Sie die C++ standard containers für alle von ihnen verwenden können (zB std::queue für die aktuelle Warteschlange, std::unordered_map für Kanäle und std::vector für die Sammlung von angeschlossenen Clients.)

Die Kunden sind sehr Es ist einfach, die Subskriptions- und Veröffentlichungsnachrichten an den Server zu senden und die Veröffentlichungsnachrichten vom Server zu empfangen. Der schwierige Teil wird wieder der eigentliche Kommunikationsteil sein.


Nachsatz:

Ich habe eigentlich nie ein solches System aufgebaut mein Selbst, alle der oben genannten nur direkt von der Spitze von meinem Kopf war. Ein erfahrener Programmierer sollte nicht mehr als ein paar Stunden brauchen, um die Grundlagen zu implementieren, vielleicht ein paar Tage für einen unerfahrenen Programmierer.

Für die Kommunikation könnten Sie z.B. Boost ASIO, verwenden Sie möglicherweise einen threads pro Kanal. Und Sie können etwas wie Boost property tree verwenden, um Nachrichten JSON oder XML zu konstruieren/parsen.

All dies ist jedoch eine Art Rad neu erfinden, wenn Sie wahrscheinlich in ein paar Stunden eines der bestehenden Systeme wie RabbitMQ verwenden könnten, sparen Sie eine Menge Zeit (und eine Menge Fehler!)

+2

Ich bin die zweite Idee, aber nur, wenn das "Framework", das Sie bauen wollen, super einfach ist und leicht sein muss, sonst .. erfinden Sie das Rad nicht neu! Ich habe diese Art von System für ein vergangenes Projekt in .NET in nur ein paar Tagen erstellt, alles inklusive. Es hat Spaß gemacht und war sehr schnell. Und da es sehr wirtschaftlich war, als wir später auslaufen mussten, warfen wir es weg und ersetzten es, ohne zurückzuschauen. In C++ würde ich auch Boost verwenden. –

4

Soweit leichte Server gehen, unterstützt Redis Pub/Sub-Befehle.

Der Redis-Code selbst ist extrem eng (nur ein paar Dateien), es ist single-threaded (verwenden Sie eine Event-Schleife), und der Speicherverbrauch ist ziemlich niedrig (im Vergleich zu anderen Queing-Systemen, die ich gesehen habe).

+1

Ich mag Redis sehr und habe es bereits als Cache/Store-Service für einige private Projekte verwendet. Nur neugierig, ob es auf einer kleinen CPU wie Himbeer PI passt? – Yoshi

+0

@Yoshi: im Vergleich zu jedem der anderen Warteschlangen-System (ActiveMQ, RabbitMQ, HornetQ, ...) ist es sicherlich eher passen. Ich wäre mehr mit RAM beschäftigt, aber Sie können immer den Lua JIT usw. entfernen, um einen leichteren Prozess zu bekommen. –

+0

Es scheint, dass redis nur gut für textbasierte Nachrichten ist. Was ist mit Binär? – liuyanghejerry

3

Ich weiß, es ist spät, aber kann für andere nützlich sein. Ich habe eine grundlegende Pub/Sub in C++ mit Boost implementiert.

CppPubSub

Die Nutzung ist sehr einfach. Von einem Ende veröffentlichen Sie Ihre Daten (generische Karte) auf einem Kanal und andere Seite abonnieren Sie für denselben Kanal und erhalten Sie die generische Karte erneut.

// you should create a singleton object of NotificationService class, make it accessible throughout your application. 
INotificationService* pNotificationService = new NotificationService(); 

// Subscribe for the event. 
function<NotificationHandler> fnNotificationHandler = bind(&SubscriberClass::NotificationHandlerFunction, this, std::placeholders::_1); 
subscriptionToken = pNotificationService->Subscribe("TEST_CHANEL", fnNotificationHandler); 

// Publish event 
NotificationData _data; 
_data["data1"] = "Hello"; 
_data["data2"] = "World"; 
pNotificationService->Publish("TEST_CHANEL", _data); 

// Unsubscribe event. 
pNotificationService->Unsubscribe(subscriptionToken);