Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » Designtechnische Frage

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
11.12.2006, 20:58 Uhr
MuteX



Guten Abend zusammen. Mein erster Post hier, ich hoffe, er genügt den Anforderungen.

Ich programmiere derzeit eine Art Proxy. Es soll hauptsächlich dazu dienen, den Datenverkehr eines Streams überwachen zu können. Also z.B. wie Tools wie Ethereal es machen, nur halt über nen dazwischengeschaltetes Proxy.

Das Ganze wird ganz in OOP realisiert. Nun ergibt sich folgendes Modell:
- die Klasse 'CTunnel' spiegelt einen - äh - Tunnel wieder. Technisch gesehen stellt ein solcher Tunnel einen Socket bereit, der auf einem bestimmten Port auf Verbindungen wartet. Sollte eine Verbindung eintreffen, bekommt die Mutterklasse (mehr dazu weiter unten) das mit, worauf sie eine anderes Objekt (vom Typ CSession) spawnt, dass sich dann um den Datenverkehr kümmert.
- die Klasse 'CProxy' verwaltet alle Tunnels und aktiven Sessions. Über sie werden auch Tunnels erstellt usw.

Also, ich möchte die ganze Geschichte natürlich über's Threading lösen. D.h. das Annehmen von Verbindungen (accept() soll blocken) und später das Empfangen von Nachrichten (recv() blockierend).

Nun frage ich mich aber: Wo soll ich am besten den Threadcode hinpacken? Denn eigentlich steuert die CProxy-Instanz ja den gesamten Rummel. Dann müsste ich mir aber "mühsehlig" merken, welches Thread-Handle zu welchem Objekt (CTunnel oder CSession) gehört und das dermaßen vorsichtig überwachen, damit nix schiefgeht und asynchron wird oder sonstwas.
Oder aber ich statte jede CTunnel- und CSession-Instanz mit einem HANDLE aus, das über eine öffentliche Funktion geholt werden kann (wobei ein Pointer darauf zurückgegeben wird, um den Wert auch manipulieren zu können). Hier wird zwar immer noch extern - also in einer CProxy-Instanz - der Thread kontrolliert. Allerdings wäre das HANDLE dann eindeutig einem Objekt zuzuordnen.

Ich hoffe, dass ich meine Problematik verständlich ausdrücken konnte und freue mich auf mögliche Antworten.

Gruß,
Stefan

Dieser Post wurde am 11.12.2006 um 21:00 Uhr von MuteX editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
11.12.2006, 21:16 Uhr
~stephanw
Gast


Also ich habe es leider nicht verstanden, aber eine Frage kann ich Dir beantworten:

Zitat:
Nun frage ich mich aber: Wo soll ich am besten den Threadcode hinpacken?

In eine Thread-Klasse. Wer auch immer seine Dienste dann mit Threads implementieren will, kann von dieser Klasse öffentlich ableiten oder privat ableiten bzw. einen Thread über eine Enthaltensein-Beziehung (member) nutzen.
Und wenn ein Proxy alles steuert, ist es dann noch ein Proxy ? Ein Proxy implementiert doch die Schnittstelle, die auch von den "echten" Klassen implementiert wird und ergänzt den Zugriff auf ein "echtes" Objekt z.B. um Schutzmechanismen. Wenn es aber zu einem sog. Proxy gar keine Alternative in Form einer ungeschützen Klasse gibt, ist es dann ein Proxy ? Mit ist durchaus bewusst, dass ein Proxy nicht nur schützen muss, sondern auch etwas vorgaukeln kann oder simulieren. Ich habe das nur als Beispiel gewählt...

Mfg
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
11.12.2006, 21:30 Uhr
MuteX



Naja, die Erstellung einer eigenen Thread-Implementation würde meine Problematik nicht lösen.

Vielleicht nochmal zum besseren Verständnis:
Ziel meines Proxys ist es, auf bestimmten lokalen Ports auf Verbindungen zu warten und sie dann, sofern eingetroffen, zu einem vorher festgelegten Host zu verbinden. Beispiel:
Proxy wartet auf Port 1234 auf eingehende Verbindungen. Client verbindet sich dorthin, woraufhin das Proxy eine Verbindung zu google.de, Port 80 herstellt. Daten von google.de gehen durch zum Client und andersrum. Das gewährleistet halt, dass ich mit dem Proxy den gesamten Datenverkehr überwachen kann.

Nun zur Problematik:
Ich habe momentan 2 Klassen teil-realisiert. Das wäre zum Einen 'CProxy' und 'CTunnel'. CTunnel ist für das Horchen auf eingehende Verbindungen zuständig und hält außerdem Informationen dafür parat, wohin es nach einer Verbindungsherstellung hingehen soll. Danach hat CTunnel nix mehr mit der Verbindung an der Mütze, es dient also lediglich der Einleitungsphase des Verbindungsaufbaus.
Damit Verbindungen angenommen werden können, muss z.B. accept() aufgerufen werden. Das geht entweder über Polling (eklig) oder in der blockierenden Variante, wozu ein Thread notwendig ist, sofern man nicht das ganze Programm anhalten möchte.
Und nun mein Problem: CProxy verwaltet u.A. alle Tunnel. Und jeder Tunnel stellt eine Funktion bereit, die das Horchen auf Verbindungen einleitet (simples accept()). Ist es nun sinnvoller/logischer, den Aufruf dieser Funktion von CProxy aus zu tätigen oder das dem Tunnel selbst zu überlassen?
Der hauptsächliche Unterschied liegt ja darin, wer den Thread verwaltet. In erstem Falle würde das CProxy-Objekt einen Thread spawnen und darin die Tunnel-Funktion für das Annehmen von Verbindungen aufrufen. Das hat den Vorteil, dass wenn eine Verbindung eintrifft, das CProxy-Objekt weiterführende Operationen innerhalb seiner eigenen Klasse leicht ausführen kann, ohne eine Zeiger-Rumgezeige in Kauf nehmen zu müssen.
Verwalten allerdings die CTunnel-Objekte den Thread, müssten sie über ein Callback dem CProxy-Objekt mitteilen, dass da was gekommen ist. Erst dann kann reagiert werden.

Ich häng halt im Moment daran fest, dass ich mir nicht sicher bin, wo was hingehört. Ich hoffe, dass das nun ein bisschen verständlicher ist.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
12.12.2006, 22:40 Uhr
~stephanw
Gast


Eine Thread-Klasse ist in jedem Fall sinnvoll aus dem einfachen Grund, dass das Erstellen eines Threads und dessen Betreuung eben nicht trivial ist und der zugehörige Code sich nicht auf Tunnel oder Proxy oder sonst wen verteilen sollte, sondern als eigenes Konzept (= Klasse) realisiert wird.
Wenn Du keine eigene schreiben willst, solltest Du eine fertige nehmen. Ich weiß nicht, welche Bibliotheken Du nimmst / nehmen kannst, damit Du das Rad nicht neu erfinden musst.

Zum fachlichen Hintergrund: so ganz habe ich es immernoch nicht verstanden, wobei das wohl an mir liegt, das ich mir noch nie klar gemacht habe, wie ein Proxy-Server funktioniert. Ist aber auch egal, Du musst nicht nochmal erklären ;-)

Eher was anders dazu:
Wenn die Klasse Tunnel eigentlich nur die Verbindung etabliert, warum heißt sie dann nicht z.B. Connector ? "Proxy" heißt Stellvertreter. Wen vertritt Proxy ? Trifft der Name "Proxy" das, was die Klasse macht oder ist der Name falsch gewählt ?

Ich kann Dir leider nur allgemeine Tipps geben:
* Wähle den Klassennamen nach der Aufgabe bzw. dem repräsentierten Konzept der Klasse. Wenn sich kein guter Name für eine Klasse/Funktion finden lässt, kann das (muss aber nicht) ein Indiz dafür sein, dass das zugehörige Konzept falsch ist (oder zu detailliert oder zu allgemein oder komplex)
* Teile Klassen eine klare Funktionalität zu. Lieber weniger als zuviel. I.A. ist Software flexibler, wenn Du mehrere kleine Klassen hast als wenige Alleskönner. Auch Konzepte wie Verbindung oder Datenstrom können als Klassen realisiert werden und muss nicht implizit in anderen Klassen verteilt sein.
* Klassen von höherem Abstraktionsniveau wie Client oder wahrsch. Dein Proxy sollten in ihren Schnittstellen kein Low-Level-Zeug wie Threads haben. Sie können diese benutzen, klar. Aber diese Benutzung sollte nicht auf verschiedene Klassen verteilt sein. Konkret: Thread-Handles oder Socket-Handles sollten nicht hin- und hergereicht werden. Wenn ein Weitergeben erforderlich ist, dann auf einer höheren Ebene wie ein "Connection"- oder "Stream"-Objekt.

Vielleicht hilft Dir das ja beim Entwurf. Vielleicht bekommst Du auch noch andere Hinweise.

MfG
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
15.12.2006, 19:04 Uhr
~MuteX_
Gast


Hallo.

Erstmal vielen Dank für die ausgiebige Antwort. Waren einige nützliche Tipps drin. Problem ist, dass ich zwar einigermaßen mit dem Design von OOP vertraut bin, aber noch nie eine größere Applikation geschrieben habe, die vollständig durch Klassen realisiert wurde.

Als "Proxy" meine ich quasi die gesamte Applikation. In anderen Bereichen könnte man Klassen "CGame", "CMailApp" oder wie auch immer nennen. Bei mir beherbergt "CProxy" den ganzen Ramsch. Ich will damit eigentlich nur erreichen, sogut wie garkeinen Code in die Main-Funktionen schreiben zu müssen, sondern wirklich 100% auf OOP zu bauen.

Wahrscheinlich hast du damit Recht, dass ich einige Funktionalitäten tatsächlich auf kleinere Klassen aufteilen sollte. Generell denke ich mir immer, was eine bestimmte Klasse leisten muss - klar. Doch wie du beschrieben hast: das ist in der Regel sehr sehr viel. Und das, obwohl ich mir schon länger Gedanken darüber mache, wie ich eine vernünftige Kapselung in meine Programme bekomme.

Und: Tunnel ist wirklich schlecht gewählt. Zutreffender wäre wohl "Listener" o.ä.

Nochmals vielen Dank für die Antwort,
Stefan
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: