Entwickler-Ecke

Delphi Tutorials - Binär-Protokoll-Tutorial (Sockets - Mal-Chat+Files)


Narses - Do 16.11.06 23:52
Titel: Binär-Protokoll-Tutorial (Sockets - Mal-Chat+Files)
Narses´ Netzwerk-Tutorials - Navigation
  1. FAQ-Beitrag: Socket-Komponenten nachinstallieren (ab D7) [http://www.delphi-library.de/topic_64438.html]
  2. Netzwerk-Basics - Minimaler Chat für Anfänger [http://www.delphi-library.de/topic_60744.html]
  3. Terminatorzeichen-Protokoll - Grundlagen (Teil 1) [http://www.delphi-library.de/topic_54269.html]
  4. Terminatorzeichen-Protokoll - Erweiterungen (Teil 2) [http://www.delphi-library.de/topic_65487.html]
  5. hier :arrow: Binär-Protokoll - Für Fortgeschrittene
  6. Netzwerk-Spiel - Multiplayer TicTacToe [http://www.delphi-library.de/topic_72573.html]
  7. UDP LAN-Chat - Der Chat ohne Server [http://www.delphi-library.de/topic_56272.html]
Binär-Protokoll-Tutorial - Für Fortgeschrittene

In diesem Tutorial wird ausführlich erläutert, was ein binäres von einem textorientierten Protokoll unterscheidet. Es wird insbesondere auf den Binärdatentransfer (Datei- und Bilddatenübertragung) eingegangen. Der Code baut auf den TServerSocket-/TClientSocket-Komponenten auf. Kleine Warnung: Das Tutorial hat ganz knapp über 100 Seiten und geht vom Anspruch her davon aus, dass man keine Probleme mit den beiden Terminatorzeichen-Protokoll-Tutorials (mehr) hat! ;)

Im ersten Teil des Tutorials wird eine universell einsetzbare Unit entwickelt, um die immer gleichen Aufgaben bei der Netzwerkkommunikation ohne großen Aufwand wiederverwendbar zu machen.

Im zweiten Teil wird eine Beispielanwendung entwickelt: Ein Client-Server-Chat-System mit Dateiübertragung (im Hintergrund; der Chat wird dabei nicht unterbrochen!) und "Gemeinsam-Zeichnen"-Funktion ("Mal-Chat").

Kurzüberblick über die Themen in diesem Tutorial:

Viel Erfolg damit,

cu
Narses


History:

V1.00 vom 16.11.2006:
Erste öffentliche Version.

Kommentare zum Tut sind hier durchaus erwünscht!

Hinweis: Falls die Anhänge unten nicht da sind, Seite (ggfs. auch mehrfach) neu laden, dann tauchen die Anhänge irgendwann auf.

Achtung! Das Tutorial ist nicht für Unicode-Delphi-Versionen geeignet (also ab D2k9). Das wird sich auch nicht mehr ändern, ist einfach zu viel Arbeit, das ganze neu zu machen. :nixweiss: Es gibt aber eine D2010-fähige Version der TNBFPA-Komponenten, siehe die folgenden beiden Beiträge. :idea:


Narses - Do 22.03.07 02:16

Moin!

Mittlerweile gibt es auch eine integrierte Komponenten-Version [http://www.delphi-forum.de/topic_71223.html] des im obigen Tutorial vorgestellten TProtocolAdapter, so dass sich die Einbindung von Protokoll-Funktionen in der Netzwerkkommunikation auf ein paar Mausklicks in der IDE beschränkt. ;)

cu
Narses


Narses - Fr 06.04.07 12:04

Moin!

Hier die Version des im Tutorial entwickelten Mal-FileTransfer-Chats mit den neuen TNBFPA-Komponenten [http://www.delphi-forum.de/topic_71223.html], um mal ein konkretes Anwendungsbeispiel im Vergleich zu haben. ;)

Die Kompos werden hier allerdings nicht voll designgerecht verwendet, weil ich so nah wie möglich am Originalcode des Tuts bleiben wollte. :mahn: Dazu mehr im nächsten Tutorial mit den Kompos. :P

cu
Narses

//EDIT: Update des Quelltextes an die Kompo-Version 1.10 (.Add(Buf,Len) -> .AddBuf())
//EDIT2: Update des Quelltextes an die Kompo-Version 1.20 (Unicode-save)


alias5000 - Fr 13.04.07 00:30

Spontan ist mir in der kompilierten Demo ein Fehler aufgefallen:
Wenn ich mit einem Client bereits ein Bild angefangen habe zu malen und dann mit einem zweiten Client verbinde und malen will, wird das bereits begonnene Bild nicht an den neuen Client gesendet. Lässt sich manuell natürlich mit Bild komplett senden wieder ausgleichen.
Vielen Dank für deine Anstrengungen! Gerade das Binär-Protokoll Tutorial fand und finde ich sehr interessant, auch wenn ich nicht von meinem Zeichenkettenprotokoll weggehen werde ;) (hat aber auch seine Gründe, BenBE hatte da ja mal in nem Thread zu neulich recht aktiv mitdiskutiert, glaub mit dir und DGL-Luke)

Gruß
alias5000


Narses - Fr 13.04.07 01:29

Moin!

user profile iconalias5000 hat folgendes geschrieben:
Wenn ich mit einem Client bereits ein Bild angefangen habe zu malen und dann mit einem zweiten Client verbinde und malen will, wird das bereits begonnene Bild nicht an den neuen Client gesendet. Lässt sich manuell natürlich mit Bild komplett senden wieder ausgleichen.

Das ist kein Fehler, das ist Design. ;) Ernsthaft, wird auch so im Tut beschrieben, da die Transferlast für das komplette Bild (wenn man´s dann auch noch in Farbe macht, ist das auch noch schlimmer!) recht hoch sein kann, wird das nur "auf Kommando" ausgeführt, damit die Serverlast nicht unnötig stark ansteigt, wenn man eine hohe Client-Fluktuation hat. :idea:

user profile iconalias5000 hat folgendes geschrieben:
Vielen Dank für deine Anstrengungen! Gerade das Binär-Protokoll Tutorial fand und finde ich sehr interessant,

Danke für das Lob! :D

user profile iconalias5000 hat folgendes geschrieben:
auch wenn ich nicht von meinem Zeichenkettenprotokoll weggehen werde ;)

Das habe ich weder erwartet noch bezwecken wollen. ;) (s.u.)

user profile iconalias5000 hat folgendes geschrieben:
(hat aber auch seine Gründe, BenBE hatte da ja mal in nem Thread zu neulich recht aktiv mitdiskutiert, glaub mit dir und DGL-Luke)

Selbstverständlich gibt es immer gute Gründe für beide Ansätze (TermChar+CounterData), deshalb habe ich ja auch beide präsentiert, um für sich und den Zweck wählen zu können. :zwinker:

Naja, eigentlich hat user profile iconDGL-luke wohl eher "mit sich selbst diskutiert" (diplomatisch formuliert), was user profile iconBenBE mehr moderiert hat :mrgreen: auf das Niveau wollte ich mich nicht einlassen... :| (scheint jemand zu sein, der zwar keinen Beitrag zum Thema leisten kann ["...hab die Grundlagen grad nicht zur Hand..."], aber schonmal weiß, dass alle anderen Unsinn reden... :gruebel:)

cu
Narses


alias5000 - Fr 13.04.07 11:47

user profile iconNarses hat folgendes geschrieben:
user profile iconalias5000 hat folgendes geschrieben:
Wenn ich mit einem Client bereits ein Bild angefangen habe zu malen und dann mit einem zweiten Client verbinde und malen will, wird das bereits begonnene Bild nicht an den neuen Client gesendet. Lässt sich manuell natürlich mit Bild komplett senden wieder ausgleichen.

Das ist kein Fehler, das ist Design. ;) Ernsthaft, wird auch so im Tut beschrieben, da die Transferlast für das komplette Bild (wenn man´s dann auch noch in Farbe macht, ist das auch noch schlimmer!) recht hoch sein kann, wird das nur "auf Kommando" ausgeführt, damit die Serverlast nicht unnötig stark ansteigt, wenn man eine hohe Client-Fluktuation hat. :idea:


Ja stimmt hast recht ;)
Wobei natürlich für eine konkrete richtige Umsetzung das dann schon irgendwie bewältigt werden sollte (also in einer "Produktivumgebung", wenn man das dann so nennen kann).
Aber daran kannste dann erkennen, wer die Demos manippuliert und wer aus dem Tutorial was eigenes entwickelt :mrgreen:

user profile iconNarses hat folgendes geschrieben:
user profile iconalias5000 hat folgendes geschrieben:
auch wenn ich nicht von meinem Zeichenkettenprotokoll weggehen werde ;)

Das habe ich weder erwartet noch bezwecken wollen. ;) (s.u.)


Hatte ich ja mit nem Augenzwinkern gesagt, war nicht wirklich ernst gemeint

Gruß
alias5000


Neotracer64 - Fr 13.07.07 01:17

Wie könnte ich jetzt am einfachsten mit den Kompos Datenübertragungen zwischen Server <> Client realisieren?
Die TUserList verwirrt mich etwas, da dort der Server ja nicht drinsteht. Sonst habe ich nirgendwo InStream und Outstream gefunden. Ein Beispiel wäre ganz nett. :)
Danke schonmal im vorraus.


Narses - Fr 13.07.07 01:33

Moin!

user profile iconNeotracer64 hat folgendes geschrieben:
Wie könnte ich jetzt am einfachsten mit den Kompos Datenübertragungen zwischen Server <> Client realisieren?

Sprichst du jetzt von den TNBFPA-Komponenten [http://www.delphi-forum.de/topic_71223.html] oder von den Socket-Kompos (TClient-/TServerSocket)? :gruebel: Abgesehen davon: es werden doch die ganze Zeit Daten zwischen Client und Server ausgetauscht. :nixweiss:

user profile iconNeotracer64 hat folgendes geschrieben:
Die TUserList verwirrt mich etwas, da dort der Server ja nicht drinsteht.

Der Server ist eine transparente Vermittlungsstelle, deshalb macht es keinen Sinn, diesen als Ziel bzw. Endpunkt für irgendwelche Übertragungen vorzusehen. :mahn: Beispiel: Du schickst ja auch keine Daten (schlussendlich) an den ICQ-Server, sondern an einen anderen Benutzer. ;)

cu
Narses


Neotracer64 - Fr 13.07.07 03:34

Hi Narses,

Ich meine deine Komponente.
Es macht schon Sinn, wenn man als Server eine Datei an mehrere Clients oder nur an einen schicken möchte.
Von Client zu Server macht es schon weniger Sinn, aber ich hatte da so eine Art CVS Idee im Kopf, wo jeder seine Projekt-Dateien auch an den Server schickt, der sie dann verwaltet und mit anderen synchronisiert. Sozusagen als Sammelstelle.
Und komm mir nicht mit dem Argument ein anderes CVS System zu benutzen, dann sage ich dir benutze ein anderes Chat-Protokoll, wie das IRC. ;)
Ich möchte einfach nur ein bisschen rumspielen und mich weiterbilden.

Vlt. hast du eine Idee für mich, wie ich also einen Server <> Client DateiTransfer mit deinen Komponenten am besten hinbekomme?

Danke schonmal im Vorraus. :)

EDIT: Ahh, sorry. Jetzt versteh ich deine Antwort. Ich meinte Übertragungen von Dateien und habe Datenübertragungen gesagt. Entschudlige, ist schon spät. ;)


Narses - Fr 13.07.07 09:34

Moin!

user profile iconNeotracer64 hat folgendes geschrieben:
Ich meine deine Komponente.

OK, dieser Thread behandelt allerdings das Binär-Protokoll-Tutorial, deshalb bitte im passenden Thread weiterdiskutieren. :mahn: ;) :arrow: Hier geht´s weiter. [http://www.delphi-forum.de/viewtopic.php?p=451215#451215]

cu
Narses


barrais - Mo 01.10.07 11:10

Hallo Narses,

ich versuche dein Protokoll-Adapter mit UDP von Indy zu realisieren(nachdem ich es aufgegeben habe, dein eigenen UDP Protokoll mit D5 zu compilieren!), das Problem ist das die Indy-UDP kein OnWrite Ereignis besitzen, kannst du mir vielleicht weiterhelfen?

Danke!


Narses - Mo 01.10.07 12:49

Moin!

user profile iconbarrais hat folgendes geschrieben:
ich versuche dein Protokoll-Adapter mit UDP von Indy zu realisieren

Ähm, ich glaube, ich habe dein "Problem" noch nicht richtig verstanden :gruebel: Du willst den in diesem Tutorial vorgestellten TCP-Protokoll-Adapter auf (Indy-)UDP umbauen? :shock: Das geht nicht; schlicht, deshalb, weil das im Tutorial verwendete Konzept TCP voraussetzt.

Es wird zwar grundsätzlich möglich sein, auch einen UDP-Protokoll-Adapter zu entwickeln, aber sicher nicht durch einen (wie auch immer gearteten) "Umbau" dieses Ansatzes hier. Das wird auf ein Neudesign hinauslaufen... :?

user profile iconbarrais hat folgendes geschrieben:
(nachdem ich es aufgegeben habe, dein eigenen UDP Protokoll mit D5 zu compilieren!)

Wenn ich es richtig gesehen habe, dann sollte sich der TUdpSockUtil [http://www.delphi-forum.de/topic_55339.html] auch unter D5 compilieren lassen, wenn du die Unit-Referenzen anpasst. Ich meine, in einem der letzen Beiträge im entsprechenden Thread [http://www.delphi-forum.de/viewtopic.php?p=458450#458450]sowas gelesen zu haben (kann auch über den Link in die DP gewesen sein).

user profile iconbarrais hat folgendes geschrieben:
das Problem ist das die Indy-UDP kein OnWrite Ereignis besitzen, kannst du mir vielleicht weiterhelfen?

Sorry, die Indy-Kompos sind leider gänzlich verschieden zu den Delphi-Sockets und auch zum TUdpSockUtil, deshalb kann ich dir da leider nicht helfen. :(

Was möchtest du denn machen? Vielleicht versuchst du ja, an der "falschen Stelle" anzusetzen? :nixweiss:

cu
Narses


barrais - Mo 01.10.07 13:21

hi,

ich habe vor, ein Anwendundungsprogramm zu implementieren, das Messdaten die über Ethernet ankommen speichert und präsentiert.Ich habe UDP ausgesucht, weil:
1. ich dadurch Broadcast Packete wegschicken kann
2. ich noch ein Mikrocontroller Programmieren muss, der diese Messungen durchführt; ein UDP-Stack ist einerseits relativ einfacher zu Programmieren und andererseits nimmt nicht viel Speicherplatz im Anspruch .
3. UDP viel schneller ist, vorallem wenn es um Grosse Datenmengen geht. und was Sicherheit angeht brauche keine Gedanken machen, weil ich das ganze in einem LAN-netz betreiben wird.

Hast du vielleicht eine Idee, wie man deinen Binären Protokoll-Adapter(übrigens: das Tutorial war sehr schön, Respekt!) auf UDP-Socket umbauen kann?

Danke!


Narses - Mo 01.10.07 15:36

Moin!

user profile iconbarrais hat folgendes geschrieben:
3. UDP viel schneller ist, vorallem wenn es um Grosse Datenmengen geht.

Das ist nicht wirklich korrekt :? Die Transferrate ist bei TCP auch nicht geringer, es gibt hier aber Timeouts, die zu beachten sind. :nixweiss:

user profile iconbarrais hat folgendes geschrieben:
Hast du vielleicht eine Idee, wie man deinen Binären Protokoll-Adapter auf UDP-Socket umbauen kann?

Wie schon gesagt, das wird nix, den Protokoll-Adapter wirst du nicht auf UDP "umbauen" können. Entscheidender Haken: du hast keinen TransferStream von der API, sondern nur Paketzustellung, also bleibt die ganze Sicherungsschicht an dir hängen. Aber, wenn ich deinen Anwendungsfall richtig einschätze, brauchst du das doch auch gar nicht. Deshalb wäre ein einfacheres, paketorientiertes Protokoll für dich möglicherweise viel besser geeignet. :idea:

user profile iconbarrais hat folgendes geschrieben:
(übrigens: das Tutorial war sehr schön, Respekt!)

Danke. :D

cu
Narses


barrais - Di 02.10.07 09:41

Hallo!

Zitat:
Deshalb wäre ein einfacheres, paketorientiertes Protokoll für dich möglicherweise viel besser geeignet.


Das hört sich sehr gut an!
hast du vielleicht zufällig ein Tutorial dazu geschrieben :roll: !
oder kennst du wo ich das finden könnte?

Vielen dank!

Moderiert von user profile iconNarses: Quote-Tag repariert


Narses - Di 02.10.07 10:25

Moin!

user profile iconbarrais hat folgendes geschrieben:
hast du vielleicht zufällig ein Tutorial dazu geschrieben :roll: !

Ich habe zwar ein UDP-Tut geschrieben (s.o. im Navigationsbereich), aber das erklärt eigentlich nur die Grundzüge. Wie du dein Protokoll entwirfst, ist natürlich etwas, das dir kein Tutorial zeigen kann - du musst schon selbst wissen, was und wie du das, was du machen willst, letztendlich umsetzt. :nixweiss: Hängt ja eben auch davon ab, was da passieren soll und welche Daten konkret transportiert werden müssen...

cu
Narses


Ravy - Fr 01.02.08 17:00

Ein dickes Lob an den Author des Tutorials. Es hat mir sehr weitergeholfen.

Vielen Dank

Ravy


der13geist - Mi 26.03.08 20:50
Titel: Kurtze verständniss frage
Moderiert von user profile iconNarses: Aus Internet / Netzwerk hier angehangen am 26.03.2008 um 23:37 Uhr

Guten Tag

Habe hier mal eine kurtze verständniss frage. Ich arbeite grade das Biär Protokoll Tutorial von Narses durch.

Nur eine frage beantwortet mir das tutorial nicht, was aber eine grundlegenheit des tutorials darstell.

der Code schnipsel

Delphi-Quelltext
1:
PInteger(@Buffer[1])^ :=                    

Also ich verstehe dies zwar aber warum wird das alles in den speicher geschrieben und nicht einfach

Delphi-Quelltext
1:
Buffer[1] :=                    

geschrieben ?

MfG
Der13Geist


BenBE - Mi 26.03.08 21:19

Benutze bitte Delphi-Tags für Source, wirkt etwas übersichtlicher ;-)

Zu besagtem Code-Schnipsel:
Durch den expliziten Typecast auf PInteger erzeugt man einen Zeiger, der auf einen Integer zeigt, der an der Stelle des Puffers platziert ist. Würde man hier einfach nur den Zugriff schreiben, so würde man auf einen Char zugreifen.

Was macht das konkret: Dadurch, dass man dem Compiler sagt, dass an besagter Speicherstelle ein Integer platziert werden soll, kümmert sich der Compiler darum, den Integer vollständig zu schreiben; man muss also nicht selber immer alles schreiben. Bei einem Char müsste man den zu schreibenden Integer erst Byte-für-Byte zerlegen und dann über den Puffer wieder korrekt zusammensetzten.

Kurz gesagt: Man erzwingt einfach eine andere Sicht des Compilers auf den Speicher ;-)


der13geist - Mi 26.03.08 21:31

Nur warum schreibt man es überhaupt in den speicher ?


BenBE - Mi 26.03.08 21:51

Buffer ist doch auch nur ein Bereich im Speicher. Und Speicher ist nix andres als ne riesig große Regalwand, wo man sich die Fächer so zusammenbauen kann, wie man se grad brauch ;-)

@Warum zuerst in den Speicher vor'm Senden: Müsste Narses eigentlich drin stehen haben ... Kann Dir aber mindestens 3 zusätzliche Gründe nennen:
- Geht schnell
- Datenbündelung
- Vermeidung kleiner Pakete


der13geist - Mi 26.03.08 22:04

nja also der Code heisst ja eig. so


Delphi-Quelltext
1:
2:
SetLenght(BinMessage, 4); 
PInteger(@BinMessage[1])^ := Lenght(Edit1.Text);


und (da ich es immer noch nicht verstanden habe) ich hätte anstatt so es so geschrieben


Delphi-Quelltext
1:
BinMessage := Lenght(Edit1.Text);                    


Aber dieses würde ja nicht funktionieren.
Habe es leider imer noch nicht verstanden :(


GTA-Place - Mi 26.03.08 23:42

Ähm... es steht doch dran warum:

1. BinMessage ist ein String
2. Die Länge des Strings soll im Binärformat in BinMessage geschrieben werden.


Delphi-Quelltext
1:
2:
BinMessage := Length(Edit1.Text);             // Geht nicht, weil BinMessage ein String
BinMessage := IntToStr(Length(Edit1.Text));   // Geht zwar, aber nicht im Binärformat


Und auf Seite 9 noch einmal ganz exakt beschrieben.


der13geist - Do 27.03.08 00:05

AHSOOO
Also ist dieser code eig. nur dazu da die länge des strings in Binär format abzuspeichern !?


Narses - Do 27.03.08 00:21

Moin!

user profile iconder13geist hat folgendes geschrieben:
Also ist dieser code eig. nur dazu da die länge des strings in Binär format abzuspeichern !?
Genau. ;) Das WARUM wird schon in Kapitel 2.3 auf Seite 6 erklärt: Rahmenbildung über Längenzähler :idea:

cu
Narses


der13geist - Do 27.03.08 00:28

aber würde ich es beim empfangen nicht in Hex umwandeln würde doch dort (Nun ja, angenommen in Edit1 steht "Hallo Welt") nur das stehen "#0#0#0#10" also dreimal ein Nullbyte und einmal ein Zeichen mit dem ASCII Code von 10 oder ?


Narses - Do 27.03.08 00:31

Moin!

user profile iconder13geist hat folgendes geschrieben:
aber würde ich es beim empfangen nicht in Hex umwandeln
Das machen wir ja nur, um es überhaupt anzeigen zu können.

user profile iconder13geist hat folgendes geschrieben:
würde doch dort (Nun ja, angenommen in Edit1 steht "Hallo Welt") nur das stehen "#0#0#0#10" also dreimal ein Nullbyte und einmal ein Zeichen mit dem ASCII Code von 10 oder ?
Nein, auch das wird in Kapitel 2.3 ausführlich erläutert: Intel-CPUs schreiben lsb-first, also steht dort: #10,#0,#0,#0. :idea:

cu
Narses


der13geist - Do 27.03.08 00:43

Danke mit diesen erkentnissen wird mir höchstwahrscheinlich alles klar. Ich werde dein tutorial noch einmal von anfang an durchlesen.
Ich danke für die Hilfe

MfG


Narses - Do 27.03.08 00:44

Moin!

Bitte, gern geschehen. :)

cu
Narses


Mann_aus_Delphi - Di 01.04.08 19:18
Titel: Ie bekomme ich überhaupt die korrekte IP?
Hey,
erstmal herzlichen Dank an Narses für das tolle Tutorial. :beer:
Ich habe fleißig gelesen und gebastelt, und getestet.
Auf meinem Lokalen Pc kann ich Verbindungen mit dem PC meines Bruders und dem meiner Mutter aufnehmen, jedoch nicht zu, sagen wir mal meinem Opa hundert Kilometer entfernt.

Ich schätze, dass die lokale IP dafür nicht taugt, aber welche dann? Die öffentliche geht auch nicht, zumindest zeigt er mir einen Verbindungsfehler an. Welche IP muss ich dafür nehmen, und wo bekomme ich sie her? :?: :?: :?: :eyecrazy: :dunce:


BenBE - Di 01.04.08 19:26

Dafür gibt es 2 Möglichkeiten:

1. Du nutzt ein VPN wie z.B. Hamachi. In dem Fall kannst Du dann die VPN-IP nutzen.

2. Ansonsten musst Du den entfernten Rechner (also der, der Server spielt) als DMZ konfigurieren (am Router) oder über Port-Forwarding (am Router) nach draußen "weiterleiten" ...

Zu zweiterem hat Narses auch bereits einen Beitrag geschrieben, wie das geht. Ersteres kann ich aus eigener Erfahrung empfehlen ;-)


Narses - Mi 02.04.08 00:01
Titel: Re: Ie bekomme ich überhaupt die korrekte IP?
Moin!

user profile iconMann_aus_Delphi hat folgendes geschrieben:
erstmal herzlichen Dank an Narses für das tolle Tutorial. :beer:
Danke für das Lob. ;)

user profile iconMann_aus_Delphi hat folgendes geschrieben:
jedoch nicht zu, sagen wir mal meinem Opa hundert Kilometer entfernt.
Hat der, der den Server stellt, einen Router im Einsatz? Dann schau mal hier [http://www.delphi-library.de/topic_Portforwarding++Eine+kleine+Einfuehrung_80904.html]. :idea:

Ansonsten könnte noch eine Firewall-Einstellung die Verbindung verhindern. :nixweiss:

cu
Narses


Mann_aus_Delphi - Mo 14.04.08 14:28
Titel: Noch ne Frage...
Ich den Clienten und den Server jetzt etwas erweitert und würde ihn nun gerne veröffentlichen (natürlich mit Bezug auf diese Seite und Narses Protokoll). Wenn Ihr, vor allem Narses, nichts dagegen habt, würde mich das wirklich sehr freuen! :lol: :lol: :shock:

Mann_aus_Delphi


BenBE - Mo 14.04.08 16:23

Solang das Rahmen-Protokoll kompatibel ist (also die Basisstruktur in der Übertragung), seh ich da wenige Probleme ... Außerdem ist ein öffentliches Tut ja dafür gedacht, dass daraus auch neue Anregungen für andre entstehen ;-)


Narses - Do 17.04.08 13:15
Titel: Re: Noch ne Frage...
Moin!

user profile iconMann_aus_Delphi hat folgendes geschrieben:
Ich den Clienten und den Server jetzt etwas erweitert und würde ihn nun gerne veröffentlichen (natürlich mit Bezug auf diese Seite und Narses Protokoll). Wenn Ihr, vor allem Narses, nichts dagegen habt,
Klar habe ich nichts dagegen. ;) Dazu eignet sich die Sparte Open Source Projekte [http://www.delphi-forum.de/forum_Open+Source+Projekte_28.html], wenn du den Quelltext dazu tun willst (was ich hiermit vorschlagen möchte :zwinker:).

cu
Narses


Pseudo - Fr 10.08.12 20:54

Sorry, dass ich das hier ausgrabe (Tut mir echt leid!),
aber ich hätte da noch eine Frage:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
procedure TNBFPAServer.ServerSocket1ClientError(Sender: TObject;
Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
   begin
     LogIt('! SID:'+IntToStr(ServerPA.ConnectionsBySocket[Socket].SessionID)+
           ' Fehler [WSA:'+IntToStr(ErrorCode)+'] aufgetreten! '+Socket.RemoteAddress);
   if (Socket.Connected) then // noch verbunden?
      Socket.Close // dann Verbindung trennen
   else // sonst...
      DeleteClient(Socket); // nur noch wegräumen
   ErrorCode := 0// Fehler behandelt, keine Exception erzeugen
end;


Hier nutzt du zum Disconnecten die Funktion Socket.Close! Wäre es nicht eig. besser hier Die Disconnect Funktion vom PA zu nutzen? bei mir kommt es mit obigem Code manchmal zu einem Fehler O.o mit Disconnect klappts wie geschmiert :D

Moderiert von user profile iconMartok: Delphi-Tags hinzugefügt


Narses - Sa 11.08.12 00:08

Moin!

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Sorry, dass ich das hier ausgrabe (Tut mir echt leid!),
aber ich hätte da noch eine Frage:
Dazu ist der Thread da, kein Problem. ;)

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Hier nutzt du zum Disconnecten die Funktion Socket.Close! Wäre es nicht eig. besser hier Die Disconnect Funktion vom PA zu nutzen? bei mir kommt es mit obigem Code manchmal zu einem Fehler O.o mit Disconnect klappts wie geschmiert
Man beachte: wir befinden uns bereits in der Fehlerbehandlung! :shock: Die spannendere Frage scheint mir eigentlich zu sein, wie es dazu kommt, dass du an dieser Stelle überhaupt die Notwendigkeit hast, die Verbindung noch trennen zu müssen (idR ist nach einem Fehler der Socket sowieso dicht oder zumindest unbrauchbar). Das Socket.Close ist da eigentlich nur noch Dichtmasse, normalerweise kommt man da gar nicht mehr hin. 8) :idea:

Aber, ich gebe zu :?, das Trennen der Verbindung im Server ist schon immer hakelig gewesen und im Nachhinein bereue ich es etwas, dass nicht per Message gelöst zu haben (es gibt da leider ein paar unschöne Probleme mit der MessageLoop, die kriegt man nicht anders in den Griff). :nixweiss:

Warum auch immer es noch (genau genommen nachträglich, weil schon in der Fehlerbehandlung) bei dir zu Fehlern kommt, die ein PA.Disconnect statt einem Socket.Close "heilt", mach es so. An der Stelle kann man eigentlich nicht mehr viel kaputt machen (die Verbindung ist dann sowieso kaputt, sonst wärst du nicht im ErrorHandler gelandet). ;)

cu
Narses


Pseudo - Mo 13.08.12 17:02

Ich hab den Ort jetzt gefunden :D
Wenn der Client mir was sendet und er genau dann per Taskmgr beendet wird kommt es (glaube ich) zu folgendem Problem:

Ich will die Instanz des PA zerstören, habe aber noch was in der Inbound Warteschlange...
Zumindest theoretisch könnte man ja einfach einen try-catch block um die komplette Procedur machen, weil das objekt danach ja eh zerstört wird, oder?
Übrigens danke für das geniale Tutorial, das hätte ich definitiv nicht ohne dich hinbekommen :D


Narses - Mo 13.08.12 17:55

Moin!

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Wenn der Client mir was sendet und er genau dann per Taskmgr beendet wird kommt es (glaube ich) zu folgendem Problem:
Ja, so ungefähr hatte ich mir die Situation vorgestellt. ;) warum auch immer man sowas machen sollte

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Ich will die Instanz des PA zerstören, habe aber noch was in der Inbound Warteschlange...
Zumindest theoretisch könnte man ja einfach einen try-catch block um die komplette Procedur machen, weil das objekt danach ja eh zerstört wird, oder?
Mach´s mit einem PA.Disconnect oder per try-except, das spielt da alles keine Rolle mehr. :nixweiss:

btw: Lass mich raten, du programmierst sonst eher in PHP, oder? :zwinker:

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Übrigens danke für das geniale Tutorial, das hätte ich definitiv nicht ohne dich hinbekommen :D
:beer:

cu
Narses


Pseudo - So 09.09.12 01:23

Falls man hier auch noch einen Tutorialwunsch äußern kann:
Wie kann ich den Server multithreaden (so, dass der ProtocolAdapter nicht komplett umgeschrieben werden muss)? Ich hab dazu bis jetzt nicht viel im Internet gefunden... Und die Indys kann ich nicht leiden (unter anderem auch weil man nur eine Zeile übertragen kann?!?). Würde mich freuen! Muss ja nicht lang sein, sondern nur kurz erklären wie man es überhaupt macht ;-)
Vielen Dank


Narses - So 09.09.12 13:58

Moin!

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Wie kann ich den Server multithreaden
Kurz gesagt: gar nicht. :nixweiss: Was du aber machen kannst: den kompletten Server in einen eigenen Thread auslagern, diesen nur für die Kommunikation verwenden (dafür reicht die Performance alle mal aus, die eigentliche Arbeit macht eh die WSA) und die Daten an Client-Worker-Threads durchzureichen. :idea:

Der Schlüssel für einen eigenen Server-Thread (klar, am Besten mit dem TNBFPAServer [http://www.entwickler-ecke.de/viewtopic.php?t=71223]) ist der wirklich geradezu geniale TMessageThread [http://www.entwickler-ecke.de/viewtopic.php?t=90333] :beer: von user profile icondelfiphan.

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Ich hab dazu bis jetzt nicht viel im Internet gefunden...
Das ist auch nicht verwunderlich. ;) Theoretisch kann der TServerSocket auch Multithreading, aber ich habe es aufgegeben herausfinden zu wollen, wie man das machen muss. Ich blicke nicht durch, was die Entwickler sich damals dabei wohl gedacht haben... :?!?: Gibt es jemanden, der das jemals geschafft hat? Wenn ja, bitte unbedigt bei mir (oder hier) melden! :lupe:

user profile iconPseudo hat folgendes geschrieben Zum zitierten Posting springen:
Und die Indys kann ich nicht leiden (unter anderem auch weil man nur eine Zeile übertragen kann?!?).
Zunächst mal: selbstverständlich kann der Socket-Wrapper (IOHandler oder so heißt das dort) der Indies auch mehr als "eine Zeile" senden (du kannst ja auch mit Streams arbeiten), aber du scheinst da was mit den Methoden zur Unterstützung von zeilenorientierten Protokollen nicht verstanden zu haben. :zwinker:

Leider muss ich aber sagen: wenn du einen "echten" Multithreaded-Server in Delphi haben willst, schätze ich ist der TidTCPServer vermutlich alternativlos. :nixweiss:

cu
Narses


Pseudo - So 09.09.12 15:12

Also ich kann veröffentlichen was ich bisher rausgefunden habe (wenig...):

Es gibt eine GetThread Procedure in der Server Komponente,
sie hat als einen "var"-Parameter (also ein call by reference) einen "TServerClientThread",
diesen muss man selbst coden (also per Thread Klasse)...

Mehr auch nicht...


Pseudo

EDIT:

Ich hab noch mehr rausgefunden, und werde vlt. wenn ichs hinkriege ein Tutorial dazu erstellen, aber ich würde gerne wissen, was die Borland Entwickler beim entwickeln der Komponente genommen haben O.o

Pseudo


Schwedenbitter - Do 08.12.16 16:29

Also mal völlig an den letzten Themen vorbei :wink: :

Ich bin gerade damit befasst, anhand des Tutorials das ganze für die Indys nachzubauen. Scheinbar ist es mir gelungen, über Umwege endlich auch einen AnsiString binär zu übertragen. Jetzt stehe ich aber vor folgendem "Problem":

Da Delphi ja (hoffentlich) nicht ohne Grund der Windows-Welt gefolgt ist und - sofern ich das richtig verstanden habe - WideString als Standard benutzt, möchte ich die mit reinbasteln - und das betrifft auch die NarsesBFPA.pas.
Bevor ich nun stundenlang durch Versuch und Irrtum eine Lösung finde, frage ich mal, ob folgender Code tendenziell funktionieren sollte:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
// einen AnsiString hinzufügen -------------------------------------------------
Procedure TCmdSeq.Add(Const Value: AnsiString);
Begin
  Add(PAnsiChar(Value)^, Length(Value));        // auf Buffer-Methode umbiegen
End;

// einen String hinzufügen -----------------------------------------------------
Procedure TCmdSeq.Add(Const Value: String);
Begin
  Add(PChar(Value)^,                    // auf Buffer-Methode umbiegen
    Length(Value) * SizeOf(Char));          // wegen 2-Byte-Character
End;

Gruß, Alex


Narses - Fr 09.12.16 17:12

Moin!

user profile iconSchwedenbitter hat folgendes geschrieben Zum zitierten Posting springen:
Bevor ich nun stundenlang durch Versuch und Irrtum eine Lösung finde, frage ich mal, ob folgender Code tendenziell funktionieren sollte:
Ich rate dringend davon ab, den hier gezeigten Ansatz (konkret: Strings als binärer Datencontainer) in Delphi-Versionen >7 zu verwenden! Dieser "Trick" (Ausnutzen der String-Compiler-Magic) funktioniert nur bis D7, so ist das Leben. Oberhalb von D7 sind meine Tutorials nur noch als Ideenquelle nutzbar. :nixweiss:

cu
Narses