Hallo zusammen,
Für mein Projekt an der Uni wird eine Verbindung mit einem externen
Server hergestellt (über Internet). Daten (aus einer Sensorik) werden
von einem Rechner (ein eingebettetes System) zu einem Server übertragen
(und dies geschieht alle 10 Sekunden). Das Client-Programm habe ich
selber in C++ realisiert. Da es sehr wichtig ist, dass auch andere Daten
neben der Kommunikation Rechner-Server verarbeitet werden, musste ich
eine asynchrone Verbindung herstellen. Daher habe ich die boost asio
Bibliotheken in meinem Programm eingebunden (insbesondere der Link hier:
http://theboostcpplibraries.com/boost.asio-network-programming war sehr
hilfreich).
Wichtig ist auch: Der Rechner sendet Daten zu dem Server und dann wartet
auf eine Rückmeldung von ihm. Bekommt der Rechner keine Rückmeldung
innerhalb einer festgelegten Frist, werden die gleichen Daten nochmal
geschickt.
*Problem*: In meiner _main_-Funktion rufe ich die Verbindung mit dem
Server einmal alle 10 Sekunden:
std::cout<<"IO Service status: "<<service_status<<std::endl<<std::endl;
17
18
}catch(std::exception&ec){
19
20
std::cerr<<ec.what()<<std::endl;
21
}
22
23
io_service_.reset();
24
25
}
26
}
Alles funktioniert wunderbar: ABER wenn ich das Zeitintervall von 10
Sekunden auf 100 Millisekunden reduziere, dann habe ich den Eindruck,
dass das Objekt resolver:
viel länger braucht und zu einer Verzögerung der Kommunikation führt.
Mir ist es noch nicht klar, wie eine Internet Verbindung mit einem
solchen Objekt hergestellt wird, daher wollte ich vor allem die folgende
Fragen:
1) soll ein solches Objekt bei jeder neuen Verbindung kreiert werden?
Also alle X Sekunden, oder reicht es vollkommen aus, wenn ich das Objekt
mit Hilfe von Smart-Zeigern in meiner Klasse deklarieren und dann der
Funktion übergeben?
Beispiel:
std::cout<<"IO Service status: "<<service_status<<std::endl<<std::endl;
15
16
}catch(std::exception&ec){
17
18
std::cerr<<ec.what()<<std::endl;
19
}
20
21
io_service_.reset();
22
23
}
24
}
Was ist erreichen will ist, dass ich das Objekt nur einmal erstellen
muss.
Ich hoffe dass meine Frage verständlich ist.
Ich möchte einfach nicht, dass die Internet-Verbindung mein ganzes
Programm abbremst, daher ist es mir wichtig, zu wissen, ob irgendwie
diese Verzögerungen vermieden werden können.
In dem obigen Link ist dieser Satz zu lesen:
In main(), boost::asio::ip::tcp::resolver::query is instantiated to
create an object q. q represents a query for the name resolver, an I/O
object of type boost::asio::ip::tcp::resolver. By passing q to
async_resolve(), an asynchronous operation is started to resolve the
name. Example 32.5 resolves the name theboostcpplibraries.com. After
the asynchronous operation has been started, run() is called on the I/O
service object to pass control to the operating system.
Daher meine Frage: Darf dieses instantiierte Objekt einmal kreiert
werden oder muss ich bei jeder neuen Verbindung mit dem Server kreieren?
(Also jedes mal dass der Rechner eine Kommunikation starten will)
Selbstverständlich bleibt der Name des Servers immer gleich.
> *Problem*: In meiner _main_-Funktion rufe ich die Verbindung mit dem> Server einmal alle 10 Sekunden:
Dein Problem ist, dass Du den code nicht vernünftig formatiert hast und
des damit potentiellen Helfern sehr schwer machst, Dir zu helfen!
Ansonsten looped dein Code busy um die 10 Sekunden verstreichen zu
lassen. Das ist absolutes no go! Du verbrennst damit CPU-Zeit und ein
ggf. vorhandener thread scheduler kann auch nicht erkennen, dass das
Blödsinn ist und ggf. einen anderen thread die CPU geben.
Boost.Asio hat auch Timer. Wenn Du 10 Sekunden warten musst, dann setze
einen timer auf und starte im callback des timers den Verbindungsaufbau
zum server. Am Ende der Verbindung setzt Du dann wieder den Timer auf.
Die einzige Haupt-Schleife im Programm sollte nichts anderes machen, als
boost::Agio::io_service::run() aufzurufen.
HTH
Torsten
Torsten!!!
Vielen Dank! Dein Tipp war super. Nachdem ich mir die boost asio
Bibliotheken angeschaut habe
(http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/tutorial/tuttimer4.html),
konnte ich innerhalb wenigen Stunden mein Programm von Null umschreiben.
Nun funktioniert alles prima!!!
Eine Sache lässt mich noch ein bisschen nachdenken. Das von mir
gepostete Beispiel, war ein sogenannte Minimal-Beispiel. Ich habe alles
sehr stark vereinfacht. In dem original Progamm habe ich 2 Loops. Die
beiden laufen mit zwei verschiedenen Takten.
In der Boost-Webseite ist ein (echt minimal-)Beispiel zu lesen. Die
beiden Loops zum Laufen zu bringen ist echt einfach.
Aber ich muss Daten zwischen den Beiden Loops austauschen können. Was
soll ich tun? mutex in dem main-Loop und jedem Loop ein eigenes thread
zuordnen?
Du kannst mal gucken, ob es für Deine Anwendung passen würde, wenn Du
die Datenänderung dadurch bewirkst, dass Du kleine Funktionen auf den
io_service post()-est, die dann die zu transportierenden Daten ändern.
Ansonsten klingt es nach keiner schlechten Idee, jeder loop einen thread
zuzuordnen.
mfg Torsten
Hi,
ich glaube ich habe es nicht so richtig verstanden, das mit der Methode
post().
Vielleicht soll ich meine Struktur und mein Design nochmal umdenken,
würde ich mich sehr freuen, wenn Du (oder Ihr) bei diesem Problem helfen
kannst.
Mit Hilfe des folgenden Tutorials
(http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/tutorial/tuttimer4.html)
war es gar nicht schwer, zwei verschiedene Klassen (Foo und Bar) zu
erzeugen und deren Methode mit einem vordefinierten Zeitintervall
systematisch aufzurufen.
/* Klasse: Foo */
Das obige ultra-mega-minimal-Beispiel funkioniert einwandfrei und ist es
auch viel eleganter als das von mir gepostete Programm.
Das Problem nun ist, dass ich in der Klasse Foo einige Methode der
Klasse Bar aufrufen muss. Es kommt somit zu einem Austausch von Daten
zwischen den beiden Klassen. Derzeit ist es unidirektional, doch werde
ich zeitnah auf die Möglichkeit zugreifen müssen, Daten in beide
Richtungen auszutauschen. Ich stehe somit vor einem Huhn-Ei Problem.
Mir fehlen nun nur zwei mögliche Lösungen ein:
*Lösung A)* In diesem Fall wird ein Istanz von Bar der Klasse Foo
als Referenz übergeben. Also:
*Lösung b)*
Beide Loops werden einzeln in einem eigenen Thread gestartet. Der
Austauch von Daten erfolgt durch den Einsatz von Mutex ...
Mich würde brennend interessieren, wie ich mein Code gestalten soll.
Danke!!!
Dave A. schrieb:> ich glaube ich habe es nicht so richtig verstanden, das mit der Methode> post().
Siehe Unten.
> Das Problem nun ist, dass ich in der Klasse Foo einige Methode der> Klasse Bar aufrufen muss. Es kommt somit zu einem Austausch von Daten> zwischen den beiden Klassen. Derzeit ist es unidirektional, doch werde> ich zeitnah auf die Möglichkeit zugreifen müssen, Daten in beide> Richtungen auszutauschen. Ich stehe somit vor einem Huhn-Ei Problem.
hast Du schon mal darüber nachgedacht, dass es evtl. besser wäre, wenn
Du nur eine Klasse mit zwei Timern hättest?
> Mir fehlen nun nur zwei mögliche Lösungen ein:>> *Lösung A)* In diesem Fall wird ein Istanz von Bar der Klasse *Foo*> als Referenz übergeben. Also:
Wenn das geht und Du sicher stellen kannst, dass das referenzierte
Objekt auch so lange lebt, wie das referenzierende Objekt, ist das eine
gute Lösung.
> *Lösung b)*> Beide Loops werden einzeln in einem eigenen Thread gestartet. Der> Austauch von Daten erfolgt durch den Einsatz von Mutex ...
Mehr als ein thread macht bei so einem asynchronen design nur Sinn, wenn
Du wirklich mehr als eine CPU auslasten kannst. Du kannst prinzipiell
die run function des io_service mit einem thread betreiben, aber auch
mit mehreren threads. Erst im zweiten Fall, must Du überhaupt damit
rechnen, dass irgend welche callbacks von verschiedenen threads
aufgerufen werden.
Wenn die Ein-Klassen-Lösung zu unübersichtlich wird, und Du vermutest,
dass Du mehr als eine CPU auslasten wirst (bzw. längere Perioden hast in
denen die CPU genutzt wird) dann könntest Du maximale Flexibilität
erreichen, in dem Du den Objekten Referenzen Ihrer Kommunikationspartner
mitgibst und diese Funktionen auf Ihren Kommunikationspartnern nicht
direkt aufrufen, sondern den Funktionsaufruf via io_service::post()
asynchron dem io_service zur Ausführung übergibst.
io_service funktioniert dann einfach wie eine Queue, irgend wann wird
der übergebene Handler indirekt von io_service::run ausgeführt.
HTH
Torsten
>> Mich würde brennend interessieren, wie ich mein Code gestalten soll.>> Danke!!!
ach und was ich vergessen hatte: Bei asynchronen designs ist es extrem
hilfreich, dass ganze als Automat zu betrachten und zu analysieren,
welche Zustände und welche Übergänge hat. Ein rein Objektorientiertes
Design führt meist nur zu Knoten im Kopf ;-)
Hi Torsten,
vielen Dank für Deine Hilfe.
Ich habe meinen Code in den letzten Tagen nochmal überarbeitet. So...mit
Deiner Hilfe und dem folgenden Tutorial:
http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/tutorial/tuttimer5.html
habe ich nun 2 Threads. Eigentlich ist es so wie Du es beschrieben hast.
Ich habe eine Klasse, welche 2 Objekte aus 2 verschiedenen Klassen
erzeugt. Diese enthalten jeweils einen Timer, welche asynchron arbeitet.
Im Grunde habe ich zwei Prozesse, welche von einander entkoppelt laufen
müssen (und mit verschiedenen Takten). Zwischen den zwei Prozessen
müssen Daten ausgetauscht werden (nach Eintreffen bestimmter
Bedingungen).
Mit dem Code bin nun relativ zufrieden, dennoch bin ich etwas irritiert,
weil ich der Meinung bin, dass das Ganze einfacherer gestaltet werden
könnte.
So...ich muss einen Schritt zurückgehen und feststellen, dass das echte
Problem in dem OOP-Design von Code liegt. Boost, Threads und alles drum
und dran ist relativ einfach und schnell zu implementieren. Doch was
einem (mir) fehlt ist ein gutes Design. Vom Anfang an. Im Internet bin
auf das Prinzip S.O.L.I.D. gestoßen, sieht und klingt es aber zu
abstract, um dessen Richtlinien einsetzen zu können.
Ich habe Deinen Lebenslauf angeschaut und wow... Du hast echt sehr viel
Erfahrung. Könntest Du mir ein Buch oder irgendwas empfehlen, um das
OOP-Design in Zukunft besser zu gestalten?
Vielen Dank nochmal.
Gruß
D.
Dave A. schrieb:> Könntest Du mir ein Buch oder irgendwas empfehlen, um das> OOP-Design in Zukunft besser zu gestalten?
Der Klassiker, wenn es um OO Designs geht ist "Design Patterns. Elements
of Reusable Object-Oriented Software.". Zur OO Analyse fällt mir leider
nichts ein.
mfg Torsten