Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailslots (https://www.delphipraxis.net/20062-geschwindigkeit-anonymous-pipes-vs-named-pipes-vs-mailslots.html)

Arakis 13. Apr 2004 08:51


Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailslots
 
Ich habe einen Serverprozess mit bis zu ca. 10 Clientprozessen, auf dem selben Computer am laufen. Es soll eine extrem hohe(!) Kommunikation in Form vom Nachrichten von 30-1000 Bytes stattfinden. Alle Prozesse haben KEIN Window.

Ein paar Geschwindigkeitsmessungen auf einem AMD 1,3 Ghz, Windows XP:
Windowsmessages von per PostThreadMessage():
ca. 150.000 Messages pro Sekunde
ca. 50.000 Messages pro Sekunde mit Warten auf Antwort

Faziz: Sehr schnell, kann aber "nur" zwei 32-Bit-Zahlen transportieren


Memory Mapped Files(Shared Memory)
Es gibt für jede Sprachrichting eine Memory Mapped File, zu sendende Daten werden hinein geschrieben und eine Windowsmessage gesendet mit Offset und Länge des Datenpacketes in der Remote-Datei um den Remoteprozess über ein neues Datenpacket zu benachrichtigen
ca. 12.000 Nachrichten(Länge 20-100 Bytes) pro Sekunde mit Warten auf Antwort
Wie lange das Senden ohne zu Warten dauert habe ich "vergessen"
Problematiken: Die "selbstgeschribene" Pipeline muss regelmäßig rotiert bzw. geleert werden.

Anomymous Pipes
2 Pipes, eine für jede Richtung. Auf beiden Seiten wird mit Hilfe von ReadFile() "gelauscht". Eine Zeitmessung habe ich noch nicht durchgeführt. Etwas anderes macht mir da "mehr" Sorgen: Serverseiting wird für jeden Client ein sperater Thread benötigt, da ReadFile() sich auf nur ein File-Handle bezieht.

Named Pipes
Ist mir ne Nummer zu "hoch", und meine Bedenken sind dass Named Pipes einen zu großen "Overhead" haben.

Mail Slots
Nachriten basiertes System. Vorteil: Es sind Broatcast-Nachrichten möglich. Nachteil: Es wird NICHT garantiert dass das Packet angekommen ist.


In meiner Anwenund gibt es folgende Nachrichtentypen:
Send Only
Beispiel: Ein Protokollierungseintrag wird abgeschickt, Der Client arbeitet sofort weiter, eine Benachrichtigung ob Erfolgreich ist nicht notwenidg
Mein Vorschlag zu Realisierung: Mail Slot oder Anonymouse Pipe in einer Richting.

Send And Notify
Beispiel: Der Client aktualisiert einen Wert auf dem Server. Als Benachrichtigung nach der Aktualisierung wäre eine Windowsmessage denkbar.

GetData
Beispiel: Ein Wert wird abgefragt. Die Anfrage wird gestellt(ca. 20-100 Bytes), es wird gewartet bis der Server Antwortet.
Mein Vorschlag zur Realisierung: zwei Anoymous Pips oder eine Named Pipe, Mail Slot oder Memory Mapped File mit windowsmessage-Benachrichtigung


Die Wahl der Transportmöglichkeit ist durch folgende Dinge zu überlegen:
- Transportgeschwindigkeit
- Effizienz beim Abfragen der ankommenden Daten

Da ich in der Regel immer in 2 Richtiungen kommunizieren muss("Send Only" ist extrem seltend, daher mache ich mir darüber jetzt keine Gedanken) ist die Situation folgende:
Die Lösung mit Memory Mapped Files-Lösung benötigt auf der Clientseiete eine MMF und eine Messagequeue, auf Serverseite ebenfalls. Auf Serverseite jedoch könnte ein einziger Thread(MessageQueue) an mehreren Verbindungen lauschen.

Für Anomous Pipes wird IMMER pro Sprachrichtung ein Thread zum lauschen benötigt.

Named Pipes sind mir ne Nummer zu "hoch"

Mit Mailslots habe ich noch nicht gearbeitet.

Nächste Problematik wäre dann das Bearbeiten der Packete auf der Serverseite. Ich bin am überlegen ob für jede Anfrage geschaut werden soll wie "zeitaufwendig" sie ist. Ist sie vorraussichtilich "zeitaufwendig" soll sie in einem neuen Thread bzw. in einem Thread im Threadpool ausgeführt werden.

Nun, was ist die schnellste und effzienteste Lösung?
Mir fehlt es halt ein bisschen an Erfahrung bei der "High Performance" Inter Process Communikation ;)

Ist als "Benachrichtiung" ein WaitHandle bzw. Event(per Handle) schneller/effizienter als eine Windowsmessage?

Gibt es eigentlich 3rd-Party Lösungen für IPC?

sakura 13. Apr 2004 09:04

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Named Pipes sind merklich langsamer. Für Messages mit 4KB Größe hast Du im Schnitt einen Durchsatz von 10.000 Nachrichten je Sekunde bei ca. 80% Prozessorauslastung (Worst-Case-Scenario!). Selbst das sollte aber eigentlich reichen. In Momenten mit solch einem Datendurchsatz sollte man das Design seiner Software überprüfen und mehrere Datenmengen bündeln ;)

Getestet mit folgenden Komponenten: http://www.delphipraxis.net/internal...?p=36961#36961 (Nicht auf Geschwindigkeit optimiert und nach jeder Verbindung wurde diese wieder automatisch geschlossen! Wenn man die Verbindung offen hält, dann kann man einen deutlich höheren Durchsatz erreichen.

...:cat:...

sakura 13. Apr 2004 09:07

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Nachtrag: Mail Slots sind ca. 30% schneller als Named Pipes aber haben den von Dir genannten Nachteil, daß die Übertragung der Nachrichten nicht garantiert ist.

...:cat:...

Arakis 13. Apr 2004 09:29

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Wie steht es mit Performance Anonymous Pipes vs Named Pipes?

Hier gibt es zwar ne Menge Infos, aber leider keine Konkrete Aussage zur Geschwindigkeit:
http://msdn.microsoft.com/library/de...unications.asp

kiar 13. Apr 2004 09:43

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
hallo ,


habe mal was gelesen, das es auch first Class mailslots gibt, die einen garantierten verbindungsorientierten Nachrichtenaustausch machen.

nur die second class mailslots garantieren keine nachrichtenübermittlung. :gruebel:

raik

sakura 13. Apr 2004 09:44

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Kann ich leider auch nicht sagen - mit denen habe ich noch nicht gearbeitet ;) Hilft nur selber testen.

...:cat:...

Arakis 13. Apr 2004 10:14

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Hm, Mailslots 30% schneller...hört sich gut an. Aber: Wenn ich nun eine eigene Benachrichtiung einbauen würde, würden dann 30% verlohren gehen?

Vorgehensweise:
Code:
Sendender Thread auf Client:
Packet Senden
WaitForSingleObject()

Empfangender Thread auf Server:
Packet abfragen
Client entsperren(Waithandle ist im Packet enthalten)
Mal ne andere Frage: Kann ein Packet lokal überhaupt verlohren gehen? :mrgreen:
Wieviel Messages(Packete) kann ein Mailslot speichern?

Wie fragt man Messages "effizent" ab? Also per Timer schon mal "sehr" schlecht ;)
Sollte der Server per WaitHandle informiert werden? Per Windowsmessage? Oder verweilt ReadFile() so lange bis eine neue Nachricht da ist?

sakura 13. Apr 2004 10:19

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Zitat:

Zitat von Arakis
Hm, Mailslots 30% schneller...hört sich gut an. Aber: Wenn ich nun eine eigene Benachrichtiung einbauen würde, würden dann 30% verlohren gehen?

Nach Milchmädchenrechnung würdest Du dadurch 40% verlieren ;)

Zitat:

Zitat von Arakis
Mal ne andere Frage: Kann ein Packet lokal überhaupt verlohren gehen? :mrgreen:

Gute Frage, nächste Frage. Ich denke mal ja.

Zitat:

Zitat von Arakis
Wieviel Messages(Packete) kann ein Mailslot speichern?

Wieder eine gute Frage... Ich glaube bis der RAM/Swap voll ist.

Zitat:

Zitat von Arakis
Wie fragt man Messages "effizent" ab? Also per Timer schon mal "sehr" schlecht ;)

Stimmt, Timer ist miserabel und langsam.

Zitat:

Zitat von Arakis
Sollte der Server per WaitHandle informiert werden? Per Windowsmessage? Oder verweilt ReadFile() so lange bis eine neue Nachricht da ist?

Schau mal in die Komponenten von oben, nach dem Schema solltest Du da schon vorgehen. (Auch mit WaitHandle).

...:cat:...

kiar 13. Apr 2004 10:25

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
vielleicht mal als denkanstoss:
http://www.entwickler-forum.de/WebX?...avZ.4@.ee6d93f


raik

Arakis 13. Apr 2004 10:50

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Zitat:

Gute Frage, nächste Frage. Ich denke mal ja
oh gott, schrecklich! Ich sehe es schon vor mir: "Ich habe Waren zu meinem Planeten gebeamt aber sie sind nicht angekommen! - Ich habe auf einem auf ein Schiff geschossen aber die Hülle ist nicht weniger geworden." Ach ja, wer sich für meine Anwendung interessiert: www.stne.net ;)

Also ich muss den Server benachritigen wenn neue Daten da sind um effizent antworten zu können, und der Server muss den Empfang auch noch bestätigen...daher stellt sich die Frage ob Anonymous Pipes bzw. Named Pipes da nicht schneller sind.

Zitat:

Schau mal in die Komponenten von oben, nach dem Schema solltest Du da schon vorgehen. (Auch mit WaitHandle).
wo?

sakura 13. Apr 2004 10:54

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Ist der Server immer auf dem gleichen Rechner wie die Client-App? Wenn ja, dann mache weiter, ansonsten wird es schon eingeschränkt. Wenn der Server im gleichen Netzwerk ist, dann musst Du mit Named Pipes arbeiten, wenn nicht einmal das der Fall ist (Internetspiele), dann musst Du über UDP bzw. TCP gehen.

...:cat:...

Arakis 13. Apr 2004 11:57

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Zitat:

Wenn ja, dann mache weiter
Was weiter machen? *kopfkratz*

Ja, wie an Anfang beschrieben, beide Prozesse sind auf dem selben Rechner. Aber ich hab ne flexible Klassenstruktur, so dass Netzwerkkommunikation hinterher auch kein Problem wäre.

Der Ebene Nach:
TNetServer - Verwaltet sämtliche Verbindungen des Anwenungssystems
TNetListener - Registriert sich beim TNetServer und erstellt auf Serverseite TNetSocket-Instanzen
TNetSocket - Transportiert Daten von einem Endpunkt zum nächsten. Z.B. über IPC, TCP, ... In diesem Thema geht es nur um diesen Punkt!
TNetTransaction - Bei einem Bytestream-orientiertem Socket werden die Nachrichten präpariert bzw. wieder zerteilt, bei einem Message orientierten Socket werden die Daten 1:1 durchgegeicht.
TNetChannal - Kleine Anwenundsprotokollebene wie z.B. die Möglichkeit Anfragen zu stellen und Antworten der Anfrage zuzuordnen(Per MessageID). Ein TnetChannel ist an EINE TNetTransaction gebunden und kann mehrere TNetRequest-Instanzen bereitstellen
TNetRequest - Anfragen senden, empfangen. Mehrere Threads/Dienste in der Client-Anwendungen erstellen ein TNetRequest.
TNetResponse - Die Möglichkeit auf Serverseite auf eine Anfrage auf Channelprotokollebene zu antworten.

Die verschiedenen Threads/Dienste verwenden wiederum ihr eigenes "Protokoll" um Daten abzufragen/Bereitzustellen.

Warum das ganz?
Meine Anwendung ist sehr Datenlastig. Eine SQL-Datenbank ist zu "langsam" (auch wenn sie optimiert ist). Also lade ich sämtliche Arbeitsdaten in den Arbeitsspeicher(Keine Archivdaten!). Es ist nur eine Frage der Zeit, dann sind 2 GB überschritten. Deshalb müssen die Daten auf mehrere Prozesse verteilt werden(64-Bit System vorrausgesetzt).
Außerdem soll wenn eine "Client" Anwendung abschmiert nicht das ganze Anwendung mitgerissen werden, denn es sind größere Skalierungen geplant.

Code:
           ----------------              --
     |-----|SQL-Datenbank |-----|         |
     |     ----------------     |         |
     |            |             |         |
     |     ----------------     |         |
     |-----| DatenService |-----|         |
     |     ----------------     |         |-- Webserver
     |            |             |         |
     |     ----------------     |         |
     |     |    Logik    |     |         |
     |     ----------------     |         |
     |       |          |       |         |
----------------      ----------------    |
|  WebService |      |  NetService |    |
----------------      ----------------   --
       |                     |
--------------------------------------
|             Internet              |
--------------------------------------
       |                     |
----------------      ----------------   --
|  Webbrowser |      |  Win32-App  |    |-- Spieler-Clients
----------------      ----------------   --
Jeder "Request" der Spieler ist eine Abfrage und/Oder eine Aktion.
Erläuterung:
WebService: Er fragt Daten direkt aus dem Datenservice oder SQL-Datenbank ab(falls Archivdaten) und stellt sie ein einer HTML-Seite bereit(lesender Vorgang). Der WebService weiß was der Spieler sehen darf und was nicht(ganz normale Webseite halt). Beisiel: Frage die Daten für Schiff 25433 ab und zeige sie in einer Webseite an. Es wird NICHT gewährleistet dass die Daten, die der WebSerivice empfängt 100% aktuell sind. Optional wird VORHER eine Aktion ausgeführt. Aktionen, also schreibende Vorgänge(meistens nur kleine Signale) werden an den Logik-Baustein weitergeleitet.

Also WebService "LIEST" aus SQL-Datenbank und Datenservice und "SCHREIBT" zum Logikbaustein. So gesehen kann der Webservice nichts "kaputt" machen und schmiert er ab - Pech

Nur der Logikbaustein ist in der Lage Daten zu verändern. Beispiel: Aktiviere die Schilde von Schiff 25433. Es wird gewährleistet, dass der Logikbaustein IMMER die aktuellsten Werte kennt/abfragen kann. Schmiert der Logikbaustein ab steht zwar das System, aber die Daten sind nocht nicht verlohren. Alle x Minuten werden nämlich Änderungen im DatenService zur SQL-Datenbank geschrieben. Außedem kann sich eine neue Instanz des Logikbausteins wieder neu verbinden. Es darf nur EINE Instanz des Logikbausteins im gesamten Anwendungssystem existieren.

Der NetService ist wie der WebService, nur dass dieser keine HTML-Seiten bereitstellt sondern die Daten in einem speziellen Spieler-Client-Protkoll.

Der DatenService ist ähnliche wie eine Relationale Datenbank und kann u.U. auf mehrere Prozess-Instanzen verteilt sein. Intern wird ein DataSet und jede Menge Indizierungen verwendet.

Die "SQL-Datenbank" sind im Grunde genommen mehrere Datenbanken, die relationale Tabellen enthält. Eine Datenbank für die Spieldaten(Beispiel Schiffe/Planeten), eine für Archivdaten(Private Nachichten), Protokollierungsdatenbank(zur Multisuche etc) und noch ein paar weitere.

In diesem Thema geht es halt um die effiziente Kommunikation von Prozess zu Prozess auf dem selben Computer! ;)

Arakis 13. Apr 2004 13:32

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Was ist nun? Hat dich der Beitrag umgehauen? :?

sakura 13. Apr 2004 15:01

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Ich muss mal antworten :shock:

Ich denke, daß Du den Ansatz noch einmal überprüfen solltest. Ist es wirklich nötig, immerzu alle Daten abzufragen :gruebel: Andere Online-Games machen dieses doch auch in Intervallen. Es kann nicht immer alles überall gleichzeitig sein - so friert Dir bei mehreren Spielern ganz schnell das gesamte Game ein, weil nur noch Daten ausgetauscht werden.

Den Ansatz welchen ich für solche Spiele kenne ist etwas anders - aber, so glaube ich, sinnvoller. Die Daten werden i.A. auf einem Game.Server gehalten. Schmiert dieser ab - Pech ;) Der berechnet auch alle Bedingungen, Computerzüge, etc.

Die Clients (Human Player) senden ihre Interaktionen an den Server und der führt die aus. Soll eine Einheit etwas machen, die es gar nicht mehr gibt... Pech, wird einfach ignoriert. Gehört dazu (und passiert selten).

Zur Darstellung des Spiels auf dem Client wird immer nur der benötigte Bereich übertragen und dem Client mitgeteilt (zzgl. etwas mehr für flüssiges Scrollen). Ausserdem können allgemeine Stati (Truppenanzahl, Geldvorrat, etc.) regelmäßig an die Clients gesandt werden (UDP, wenns verloren geht: na und ;) )
Hin und wieder wird an alle Clients der gesamte Datenbestand übermittelt, damit es beim Absturz des Servers reibungsfrei weitergehen kann (neuer Server muss ermittelt werden).

Dein Ansatz würde einfach die gesamte Rechenpower auf die Kommunikation legen. Sämtliche Restzeit für KI, GFX, Sound, Spielerinteraktion würde einfach zu knapp werden.

...:cat:...

Arakis 13. Apr 2004 16:28

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Wie ich schon sagate, NUR der Logikbaustein muss die aktuellen Werte haben. Dieser Fragt die Daten von DatenService ab und behält sie kurzfristig in einem Cache.

WebService und NetService beötigen keine aktuellen Werte, wird eine Webseite mit falschen Daten herausgegeben - Pech.

Ebenfalls haben die Win32-Spieler-Clients keine aktuellen Werte. Die Werte werden zwischengespeichert und nur "seltend" aktualisiert.

Von daher ist mir nicht ganz klar was man da optimieren kann. "Andere" Onlinespiele greifen z.B. permanent und für jede Kleinigkeit auf eine SQL-Datenbank zu, die "Anwendung" in Form einer php.exe mit einem Script gesteuert, nach der Ausführungt wird die Anwndung terminiert und vergisst alles nicht gespeicherte. Gut, ich verwende zwar ASP.NET, aber nenne mir den Unterschied:

Ob ich nun z.B. für die Planetenübersicht ein SQL-Befehl an die SQL-Datenbank sende den Datenservice frage......zweites dürfte von der Performance schneller sein, Vorraussetzung ist natürlich eine vernüntige Implementierung der IPC-Sockets.

Also noch mal zusammenggefasst:
WebServcie und NetService greifen direkt auf die SQL-Datenbank und DatenService zu, wie es jede normale z.B. PHP-Seite auch machen würde. Die Daten brauchen nicht aktuell zu sein. Ab und zu Senden WebService und NetService dem Logikbaustein einen Befehl zu...nichts besonderes. Knackpunkt ist halt die Kommunikation zwischen Logikbaustein und DatenService, aber der Logikbaustein wird eh weniger belastet werden als die Anderen Prozesse, da eine Aktion meistens erst nach 3-5 Webseitenaufrufen oder anch unzähligen Abfragen der Win32-Spieler-Clients stattfindet.

Warum nicht alles in einem Prozess lassen so wie es jetzt ist?
- Weil die Arbeits-Daten irgendwann größer als 2 GB sein werden. Es ist nur eine Frage der Zeit-
- Die Trägheit der Datenbank könnte Cheating ermöglichen. Es sind zwar Sperren auf Datensatz ebene möglich, jedoch zieht das die Performance ernorm herunter, vor allem bei einem MMOG(Massen Multiplayer Online Game)

Warum nicht alles in eine Datenbank packen und es wie die klassichen PHP-Seite machen?
- Auf die Software zugeschnittene Indizierungen sind wichtig und sparen eine Menge Abfragezeit(zumindest im Moment). Beispiel: Jeder Planet hat eine Oberfläche von 7x10 Feldern + Orbit von 2x10 Feldern. Um nun die Kolonieübersicht anzuzeigen wären folgende Möglichkeiten denkbar:

SELECT * FROM Planets WHERE user_id=x;
für jeden Planet im Ergebnis: SELECT * FROM fields WHERE field_planet_id=x
Sehr langsam.

Daher verwende ich z.b. zur Zeit eine HashTable. Key: PlanetID, Value: Array of DataRow (der Fields, sind in der Regel 70 Stück)
Die Hashtable speichert die Oberflächen zwischen - Schnellste Möglichkeit

oder:
SELECT * FROM planets, fields WHERE planet_id=field_planet_id AND planet_user_id=x
Es werden zu viel Daten abgefragt

oder:
Man füge der Tabelle fields eine UserID hinzu:
SELECT * FROM Planets WHERE user_id=x;
SELECT * FROM fields WHERE field_user_id=x;
Sehr schnell, jedoch ist die fields-Tabelle auf eine bestimtme Abfrage optimiert worden. Da fields zu planet gehört und planet den Besitzer kennt ist es grauenvoll in der fields-Tabelle den Besitzer ebenfalls zu speichern.

Oder:
SELECT * FROM Planets WHERE user_id=x;
SELECT * FROM fiels WHERE field_planet_id=y1 OR field_planet_id=y2 OR ....
Auch ne Möglichkeit, habe ich aber ehrlichgesagt noch nicht ausprobiert, war bisher ja auch nie nötig.



Geschwindigkeitsmessung: Microsoft SQL-Server schafft ca. 500 Planetenoberflächen abzufragen. Ein Spieler könnte aber ca. 100 Planeten haben. Und wenn es nur die Planetenoberflächen wären.....dies war ein Beispiel von vielen. Gemessen auf einem 2 Ghz Celeron.

Falls wir uns mißverstanden haben sollten: Der Datenservice stellt ganze Datensäzte bereit, es werden keine Felder in Echtzeit abgefragt(Das wären nämlich "nur" ca. 50.000 Variabelabfragen PRO Webseitenaufruf für einen Spieler der NUR 6 Planeten hat). Der DatenService informiert den WebService und NetService nur bei einer Änderung(Windowsmessage), WebService und NetService müssen dann selber schauen ob sie nun ein Refresh des Datensatzes machen(Wird nur für bestimmte Objekte notwendig sein wie z.B. die Galaxie-Übersicht).

Zur Zeit schafft der DatenService ca. 6000 Datensatz in der Sekunde, wenn über die RowID gegangen wird. Ob es nur eine Row ist oder 70, das spielt dabei eine relativ kleine Rolle, die Serialisierung geht sehr schnell, die Datenbank bleibt auch unbedeutend klein. Der DatenService schafft ca. 12.000 Zeilen-Updates, jedoch ohne dass der Client wartet. Gemssen auf einem 1,3 Ghz AMD.

Ich schließe natürlich nicht aus dass ich einen Designfehler in meiner Software habe, für Tipps bin ich gern hellhörig ;)

Arakis 15. Apr 2004 00:04

Re: Geschwindigkeit Anonymous Pipes vs Named Pipes vs Mailsl
 
Zitat:

Zitat von sakura
Schau mal in die Komponenten von oben, nach dem Schema solltest Du da schon vorgehen

Wo?

Zitat:

Zitat von sakura
Ist der Server immer auf dem gleichen Rechner wie die Client-App? Wenn ja, dann mache weiter, ansonsten wird es schon eingeschränkt.

Was weiter machen?


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:53 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz