AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke Delphi Konzept: Netzwerkprotokoll
Thema durchsuchen
Ansicht
Themen-Optionen

Konzept: Netzwerkprotokoll

Offene Frage von "BUG"
Ein Thema von Zacherl · begonnen am 18. Sep 2012 · letzter Beitrag vom 25. Sep 2012
Antwort Antwort
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#1

AW: Konzept: Netzwerkprotokoll

  Alt 18. Sep 2012, 19:54
Hier ist auch schon die erste Sache, die mich etwas stört: Der Thread verbraucht, durch die Schleife bedingt, relativ viel CPU Zeit. Das Sleep(1) schafft schon etwas Abhilfe, verringert natürlich aber auch deutlich die Übertragungsgeschwindigkeit.
Vielleicht sollte man das über die Thread-Priorität regeln.

Die anderen Dinge würde ich wie folgt angehen:

Brauchst du wirklich mehr als 2^16 Verbindungen? Schon eine 2^16 Lookup-Table ist imho ziemlich groß.

Dann würde ich vorschlagen, dass der Empfänger das erste Paket bestätigen muss ... damit gibt er bekannt, das er genug Ressourcen (und Fähigkeiten*) für diese Verbindung hat und das der Schlüssel richtig ist. Im ersten Paket gibt es bei verschlüsselten Verbindungen eine verschlüsselte Zufallszahl (Challenge), die der Empfänger entschlüsselt** wieder zurücksenden muss. Wichtig wäre dabei: Priorisierte Nachrichten sollten immer eine vorbereitete Verbindung haben.

Wenn du die Zuordnungstabelle auf Empfängerseite besser verwalten willst, dann lass den Sender eine eigene Nummer zurücksenden, die der Sender ab jetzt benutzen soll. Der Empfänger meldet sich weiter mit der ursprünglichen ID an den Sender.

Wenn der Sender oder Empfänger eine Verbindung (Chancel) abbrechen wollen, schicken sie ein Paket, das auch den Grund nennt (User/Fehler/...). Das kann er auch senden, wenn er die Verbindung nicht haben will.


*Das gibt dir die Möglichkeit, eine light-Version des Protokoll zu benutzen, z.B. ohne Kompression.
** Achtung: Gute Verschlüsselung verwenden.
Intellekt ist das Verstehen von Wissen. Verstehen ist der wahre Pfad zu Einsicht. Einsicht ist der Schlüssel zu allem.

Geändert von BUG (18. Sep 2012 um 19:57 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#2

AW: Konzept: Netzwerkprotokoll

  Alt 18. Sep 2012, 20:26
Hallo BUG, danke für deine Antwort.

Vielleicht sollte man das über die Thread-Priorität regeln.
Gute Idee

Brauchst du wirklich mehr als 2^16 Verbindungen? Schon eine 2^16 Lookup-Table ist imho ziemlich groß.
Ich bezweifele es, würde aber trotzdem lieber auf Nummer sicher gehen.

Dann würde ich vorschlagen, dass der Empfänger das erste Paket bestätigen muss ... damit gibt er bekannt, das er genug Ressourcen (und Fähigkeiten*) für diese Verbindung hat und das der Schlüssel richtig ist. Im ersten Paket gibt es bei verschlüsselten Verbindungen eine verschlüsselte Zufallszahl (Challenge), die der Empfänger entschlüsselt** wieder zurücksenden muss. Wichtig wäre dabei: Priorisierte Nachrichten sollten immer eine vorbereitete Verbindung haben.
Im Prinzip auch eine Gute Idee. Vorbereitete Verbindungen sind immer schwierig, da ich mir nie sicher sein kann wie viele priorisierte Nachrichten unter Umständen gleichzeitig geschickt werden. Das Challenge und Capabilities Ping Pong Prinzip werde ich wohl als extra Funktion einbauen, um die Verschlüsselung und Kompression abzusichern. Allerdings werde ich es hier so handhaben, dass entweder der Client oder Server (je nachdem wer das erste Paket sendet) hier manuell tätig werden muss. In einem Event signalisiere ich dann auf beiden Seiten, dass die Verbindung abgesichert ist. Danach erst können "normale" Pakete gesendet werden.

Wenn du die Zuordnungstabelle auf Empfängerseite besser verwalten willst, dann lass den Sender eine eigene Nummer zurücksenden, die der Sender ab jetzt benutzen soll. Der Empfänger meldet sich weiter mit der ursprünglichen ID an den Sender.
Kannst du eventuell eine Vermutung bezüglich der Performance antizipieren? Das Protokoll soll unter anderem in einem Reverse SOCKS5 Proxy zum Einsatz kommen. Bei meinem ersten Versuch habe ich pro Verbindung ein neues Socket erstellt, dann die Challenge ausgetauscht und dann mit der Datenübertragung begonnen. Das war enorm langsam. Bin mir aber nicht sicher, ob es an den immer neuen Sockets (ohne Thread Pool etc) lag oder am Key Exchange.

Wenn der Sender oder Empfänger eine Verbindung (Chancel) abbrechen wollen, schicken sie ein Paket, das auch den Grund nennt (User/Fehler/...). Das kann er auch senden, wenn er die Verbindung nicht haben will.
Klingt nett. Bisher habe ich ein Flag für Suspend, Resume und Cancel vorgesehen. Dort könnte ich im Datenteil des Pakets mit Leichtigkeit noch eine Fehler ID übertragen.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#3

AW: Konzept: Netzwerkprotokoll

  Alt 18. Sep 2012, 20:55
Kannst du eventuell eine Vermutung bezüglich der Performance antizipieren? Das Protokoll soll unter anderem in einem Reverse SOCKS5 Proxy zum Einsatz kommen. Bei meinem ersten Versuch habe ich pro Verbindung ein neues Socket erstellt, dann die Challenge ausgetauscht und dann mit der Datenübertragung begonnen. Das war enorm langsam. Bin mir aber nicht sicher, ob es an den immer neuen Sockets (ohne Thread Pool etc) lag oder am Key Exchange.
Discleamer: Ich habe keine praktischen Erfahrungen im Protokolldesign, sondern zehre von einer mageren Netzwerkvorlesung

Wenn du kleine Datenmengen (HTTP) pro Verbindung gesendet hast, dann würde ich vermuten, das der Aufwand für eine neue Verbindung (Handshake, usw.) mit rein spielen könnte. Aber auch ein Key-Exchange nötigt dir ja mindestens eine Round-Trip-Time als Wartezeit auf.

Mal so aus Interesse: Wo genau kommt denn das Protokoll ins Spiel?
Intellekt ist das Verstehen von Wissen. Verstehen ist der wahre Pfad zu Einsicht. Einsicht ist der Schlüssel zu allem.
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

AW: Konzept: Netzwerkprotokoll

  Alt 18. Sep 2012, 21:07
Wenn du kleine Datenmengen (HTTP) pro Verbindung gesendet hast, dann würde ich vermuten, das der Aufwand für eine neue Verbindung (Handshake, usw.) mit rein spielen könnte. Aber auch ein Key-Exchange nötigt dir ja mindestens eine Round-Trip-Time als Wartezeit auf.
Exakt. Meine Vermutung war auch eher, dass das Aufbauen der TCP Verbindung die meiste Zeit in anspruch nimmt. Habe damals leider versäumt es ohne den Key Exchange zu testen. Der Sourcecode ist unvorteilhafterweise auch mittlerweile im Nirvana verschollen.

Hat vielleicht noch jemand anders hiermit Erfahrungen gemacht?

Mal so aus Interesse: Wo genau kommt denn das Protokoll ins Spiel?
Primär wollte ich das Protokoll in einem reverse Proxy für Browser verwenden. Priorisierung kommt dann ins Spiel, wenn man darüber beispielsweise richtig Dateien runterläd. Dann sollen die normalen Website Downloads normal weiterlaufen, während aber nach 3 parallelen Datei Downloads erstmal Schluss ist.
Mein zweiter Ansatz lief damals schon über eine frühe Version meines Protokolls, was ich hier zu optimieren versuche. Hierbei wurden die Websiten in jedem Fall deutlich schneller aufgerufen, als bei der Multi Socket Variante. Dort war aber auch kein Key Exchange enthalten, deshalb habe ich hier wieder keinen direkten Vergleich.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#5

AW: Konzept: Netzwerkprotokoll

  Alt 19. Sep 2012, 14:36
Also ich habe mir dazu auch schon mal Gedanken gemacht und bin auf folgendes Protokoll gekommen:
Delphi-Quellcode:
TMessageHeader = packed record
  BlockSize: Word; // Größe des aktuellen Datenblocks (inkl. Header)
  StreamNo : Byte; // 0=Command Stream, 1..255=Data Streams
  Payload : Array[0..0] of Byte; // Nutzdaten
end;
Damit können bis zu 256 unabhängige Streams über die gleiche TCP-Verbindung gemultiplexed werden.
Nach Aufbau der TCP/IP-Verbindung ist nur der Command-Stream (0) offen.
Der Client sendet dann z.B. einen Befehl an den Server:
Code:
SENDFILE test.dat
Der Server antwortet
Code:
ACK Stream 2
Die Daten werden dann blockweise mit StreamNo=2 übertragen.
Zum Schluss wird eine Message ohne Payload geschickt um den Stream wieder zu schliesen.

Der Charme dieses Protokolls ist seine Einfachheit. (das Protokoll im Command-Stream gehört aber nicht dazu. Das SENDFILE oben war nur ein Anwendungsbeispiel)
Man kann es unabhängig vom Einsatzzweck benützen.
Andreas

Geändert von shmia (19. Sep 2012 um 14:39 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#6

AW: Konzept: Netzwerkprotokoll

  Alt 19. Sep 2012, 15:56
Habe noch bis früh heute morgen am Protokoll gearbeitet und einige Ideen von hier wieder verworfen, geändert oder neue Sachen hinzugefügt. Das Senden und Empfangen ansich funktioniert nun schon überraschend gut. Fehlen nur noch einige Events, das automatische Sammeln der Daten, ein paar Fehlerkorrekturen und ausführliche Tests.

Meine Hauptpakete sind folgende:
Delphi-Quellcode:
type
  TdxIDTPPacketType = (
    ptTransferInfo = 1,
    ptTransferData = 2,
    ptTransferStateChanged = 3,
    ptTransferStateCommand = 4
  );
  
  TdxIDTPMainHeader = packed record
    TransferID: Word;
    PacketSize: Word;
    PacketType: TdxIDTPPacketType;
  end;

  // Diesem Paket folgen direkt die Meta Daten, fals vorhanden
  PdxIDTP1Packet = ^TdxIDTP1Packet;
  TdxIDTP1Packet = packed record
    Magic: DWord;
    MetaSize: Word;
    DataSize: UInt64;
    BlockSize: TdxIDTPBlockSize;
    Priority: Boolean;
    Encrypted: Boolean;
    Compressed: Boolean;
  end;

  PdxIDTP2Packet = ^TdxIDTP2Packet;
  TdxIDTP2Packet = packed record
    Magic: DWord;
    TransferState: TdxIDTPTransferState;
    Reason: TdxIDTPTransferStateChangeReason;
  end;
Der Main Header enthält wie vorher die ID der Übertragung, die aktuelle Blockgröße und den Typ der folgenden Daten.
ptTransferInfo ist praktisch das Initialisierungspaket für einen neuen Transfer. Es enthält das TdxIDTP1Packet gefolgt von eventuellen Meta Daten. Der Empfänger reagiert auf das Paket, indem es ein neues Transfer Objekt anlegt und in der LookupTable einträgt
ptTransferData enthält jeweils einen Datenblock eines Transfers. Der Empfänger prüft, ob der Transfer in der LookupTable vorhanden ist und akkumuliert die Daten. Wenn die TransferID nicht existiert, wird das Paket schlicht und einfach verworfen.
ptTransferStateChanged wird vom Sender geschickt, wenn der User eine Übertragung pausiert, fortsetzt oder abbricht. Der Empfänger ändert auf seiner Seite dann ebenfalls den Status des Transfers. Wenn die TransferID nicht existiert, wird auch hier das Paket einfach verworfen.
ptTransferStateCommand wird vom Empfänger an den Sender geschickt, wenn der User eine Übertragung pausiert, fortsetzt oder abbricht. Der Sender antwortet darauf mit einem ptTransferStateChanged Packet.

Das Magic Feld in den Control Paketen beinhaltet einen festen Wert, welcher nach der Entschlüsselung geprüft wird. Ist der Wert falsch, kann davon ausgegangen werden, dass unterschiedliche Verschlüsselungroutinen oder Schlüssel zum Einsatz kommen. Die Pakete werden dann auf Seite des Empfängers verworfen (hier könnte man sich eventuell noch etwas überlegen, um den Sender zu informieren).

Die Ping Pong Variante beim Start eines Transfers habe ich komplett verworfen. Ausgehend davon, dass die LookupTabelle auf Sender und Empfängerseite eigentlich immer synchronisiert sein sollte, kann der Sender bereits feststellen, ob bereits 2^16 Transfers laufen. Die Funktion zum Ermitteln der nächsten freien TransferID ist folgender:
Delphi-Quellcode:
function TdxIDTPIOHandler.SearchNextTransferID(var TransferID: Word): Boolean;
var
  I: Word;
begin
  Result := false;
  if (FLastTransferID = MAXWORD) then FLastTransferID := 0;
  for I := FLastTransferID to High(FOLookupTable) do
  begin
    if not Assigned(FOLookupTable[I]) then
    begin
      TransferID := I;
      Result := true;
      FLastTransferID := TransferID;
      Exit;
    end;
  end;
  for I := Low(FOLookupTable) to FLastTransferID do
  begin
    if not Assigned(FOLookupTable[I]) then
    begin
      TransferID := I;
      Result := true;
      FLastTransferID := TransferID;
      Break;
    end;
  end;
end;
Schlägt die Funktion fehl, wird eine Exception geschmissen.

Was sagt ihr zur bisherigen Umsetzung? Auf den ersten Blick scheint mir das Protokoll recht stabil zu funktionieren. Seht ihr noch irgendwelche Sachen, die extrem umgeschickt gelöst sind?
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Furtbichler
(Gast)

n/a Beiträge
 
#7

AW: Konzept: Netzwerkprotokoll

  Alt 24. Sep 2012, 06:43
Wenn Du mit 2^16 Übertragungen rechnest, solltest Du deine Lookuptabelle nicht als unsortiertes Array konzipieren. Verwende lieber doppelt-verkettete Liste für die freigegebenen Sende-IDs.

Delphi-Quellcode:
Function GetNewID : Integer;
Begin
  If FreeList.IsEmpty Then begin
    If HighestID = MAXWORD Then Raise Exception....;
    HighestID := HighestID + 1;
    Result := HighestID;
  End
  else Begin
    Result := FreeList.First;
    FreeList.RemoveFirstElement;
  End;
End;

Procedure DiscardUsedID (aIDWhichIsNoLongerInUse : Integer);
Begin
  FreeList.InsertAtFront(aIDWhichIsNoLongerInUse);
End;
So ist der Aufwand immer O(1), anstatt O(n) bei deiner Variante.
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:59 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