Autor Beitrag
der_zaehe
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 317

WinXP SP2
D6 Pers, D2005 Prof, VS2005
BeitragVerfasst: Mi 02.02.05 16:46 
Wie genau kann ich einen beliebigen, selbstdefinierten record mit TClientSocket/TServerSocket verschicken? Soviel ich weiß (und das ist nicht so viel :? ) braucht man dazu mindestens .SendBuf und .ReceiveBuf . Die Suchfunktion hat nicht soviel nützliches ergeben, entweder wollten die leute da alle dateien versenden, oder haben interessante Formen von Streams benutzt, die ich leider alle nicht verstanden hab. Mein Info-Lehrer hat vom versenden/empfangen via buffer leider auch keine Ahnung.

Ich habe dieses Problem hier schon mal unter "Versenden eines records mit TClientSocket/TServerSocket" (www.delphi-forum.de/...verSocket_35388.html) gepostet, dort hatte mir jemand den Vorschlag gemacht, den Text ("damals" nur Text), einfach mit Trennzeichen zu versehen, in einen einzigen großen String zu tun, den dann mit .SendText zu verschicken, und beim empfang wieder auseinanderzupulen. Hervorragende Idee, hat bis jetzt auch gut funktioniert. Jedoch wird das chat-programm, in dem das alles zum einsatz kommt, etwas komplexer, ich habe mit einigen mir vollkommen unerklärlichen bugs zu kämpfen und habe jetzt auch keinen richtigen durchblick mehr, da das trennen und wieder zusammensetzen in ein heilloses gewurschtel ausartet. :shock:

Ich wär euch echt dankbar für jeden vorschlag, der mich meinem ziel näher bringt.

//Ich weiß schon, es wäre besser, wenn ich hier code zum verbessern reinstellen würde, aber ich hab schlicht und weg
//absolut keine plan wie ich das coden soll, nicht mal den ansatz eines ansatzes. :(

_________________
[inspirationslos]
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 03.02.05 00:16 
Moin!

Da du auch ausdrücklich nach anderen Lösungen für dein Problem gefragt hast, will ich nochmal was dazu sagen. Zunächst mal, ich würde dir ganz dringend von dem Record-basierten Ansatz eines Protokolls abraten! Du legst dich da viel zu sehr auf eine spezielle Kommunikationsart fest, mit so einem proprietären Protokoll auf Record-basis, das wird dich früher oder später maßlos ärgern, wenn du das wirklich anfassen solltest. Deshalb will ich erstmal dazu nix weiter sagen.

Statt dessen würde ich gerne nochmal den Strings-Ansatz verfeinern: Du hast sicherlich nicht sowas wie ein Kommunikationsprotokoll definiert, oder? Statt dessen gehst du im Code von einer bestimmten Reihenfolge in den Strings aus und ordnest diesen darüber eine Bedeutung zu (ins Blaue geraten). Sollte das in etwa zutreffen, dann wundert es mich nicht, wenn du da ein "gewurstel" bekommst.

Besser wäre es, wenn du einen Satz von Kommandos definierst, die gegebenenfalls mit Parametern versehen sind, um Nutzdaten zu transportieren (ich mach gleich ein Beispiel). So kannst du den Datenfluss auch "manuell" debuggen, indem zu einfach stumpf alles was rein oder raus geht, in eine Datei schreibst (als Text).

Wir definieren mal ein Beispiel-Protokoll für einen Chat (Parameter in eckigen Klammern), zunächst aus Client-Sicht:

1. login [user] [pass]
Benutzer anmelden

2. logout
Benutzer abmelden

3. send [text]
Eigenen Text senden

4. list
Angemeldete Benutzer des Servers auflisten

Soweit zu den Kommandos, die der Client absetzen könnte. Jetzt die Serverantworten bzw. Kommandos:

5. ok
Letztes Kommando erfolgreich (z.B. login oder send)

6. error
Letztes Kommando war NICHT erfolgreich

7. message [user] [text]
Benutzer hat eine Nachricht gesendet

8. quit
Zwangsabmeldung vom Server (z.B. weil der Server dicht macht)

Ich denke, soweit sollte klar sein, was damit gemeint ist und wie das Konzept aussieht. Ob das (Beispiel-)Protokoll so brauchbar ist oder nicht, ist hier nicht wichtig, es geht nur um das Prinzip.

Das Parsen der empfangenen Strings läßt sich sehr einfach mit .DelimitedText der StringList erledigen, wenn man vorher .Delimiter := #32 setzt. Jetzt hat man in den Strings der Liste die einzelnen Elemente des empfangenen Kommandos und kann entsprechend darauf reagieren, und zwar auf das Kommando/Antwort im ersten String!

Auf der andern Seite kannst du zum Senden der Strings auch eine StringListe benutzen, in die du die einzelnen Elemente addierst und dann mit (.Delimiter := #32) .DelimitedText daraus den zu sendenden Text machst.

Ein häufig anzutreffender Fehler ist folgender: Wenn ein Client viele Daten kurz nacheinander sendet, dann landen die Strings "verkettet" im Buffer des Serversockets und du liest praktisch zwei Texte auf einmal aus. Du kannst diesen Effekt dadurch umgehen, dass du einfach an jeden zu sendenden Text noch ein Leerzeichen anhängst.

Ein auf diese Weise etabliertes Protokoll ist sogar (in gewissen Grenzen) kompatibel zu Erweiterungen in späteren Versionen, dagegen kommt es bei einer Änderung in der Record-Struktur immer zu einem inkompatiblen Protokoll (was man ggfs. noch nicht mal bemerkt und dann zu unvorhersehbaren Effekten führen kann; also Client hat Version 1 des ComRecords, der Server aber schon 3 z.B.)!

Ich hoffe, du kannst mir folgen und was ich da so von mir gebe, ist einigermaßen verständlich gewesen. :wink:

cu
Narses
der_zaehe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 317

WinXP SP2
D6 Pers, D2005 Prof, VS2005
BeitragVerfasst: Do 03.02.05 16:55 
hi narses!
danke erst mal dafür, das du dir die mühe gemacht hast, soviel zu posten. Ich war schon ganz verzweifelt, weil einfach keine Antwort kam. Ich hab mir deinen Vorschlag genau durchgelesen und finde die idee sehr überzeugend. Jedoch habe ich noch zwei Fragen: Wie kann ich das verschicken von dateien realisieren? (Ich meine parallel zum Text, wies theoretisch geht hab ich da www.delphi-forum.de/...erschicken_2632.html her.)Könntest dur kurz nen Beispiel für das login machen? ich meine wie der zusammengesetzte string dann aussieht, bzw. wie ich die einzelnen strings dann rauspflücke. Ich hatte das in meinem chat bis jetzt ziemlich so genau gemacht, wie du es geraten hattest.

trotz allem ,selbst wenn ichs jetzt per string versende, fänd ichs gut, wenn du mir das mit dem buffer kurz erklären könntest (vorausgesetzt natürlich, dass das nicht zu kompliziert oder zu viel zu schreiben ist.) Das soll aber nicht heißten, das ich es dann immer per buffer versende, ich finde die idee mit dem protokoll deutlich besser. :)

_________________
[inspirationslos]
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 03.02.05 21:53 
Moin!

der_zaehe hat folgendes geschrieben:
Ich war schon ganz verzweifelt, weil einfach keine Antwort kam.

Naja, Antworten werden ja hier nicht am Fließband geschrieben... :wink: Ich finde, du musstest jetzt nicht übermäßig lange warten, oder?

der_zaehe hat folgendes geschrieben:
Wie kann ich das verschicken von dateien realisieren? (Ich meine parallel zum Text

Das ist keine leichte Angelegenheit, wenn man das (vernünftig!) parallel zum Chat implementieren will. Ehrlich gesagt würde ich dir raten, zunächst mal die Sache mit dem Protokoll umzusetzen, dass mit dem Filetransfer baut eh darauf auf. (paar Stichworte für Ungeduldige: ich würde das wie beim FTP-Protokoll aufziehen, mit einer separaten Verbindung und einem separaten Thread; wie gesagt, das vernünftig zu machen ist nicht ganz trivial; Alternative: einen Befehl für Dateisegmente mit einer festen Länge wie Chat-Nachrichten versenden, dann haste aber auch die ganze Arbeit der Sicherungsschicht...)

der_zaehe hat folgendes geschrieben:
Könntest dur kurz nen Beispiel für das login machen? ich meine wie der zusammengesetzte string dann aussieht, bzw. wie ich die einzelnen strings dann rauspflücke.

Hm, weiß jetzt nicht so genau, was ich da erklären soll?! Ist doch dein Protokoll, mach´s so, wie du willst. Ich könnte jetzt sowas schreiben, aber was nutzt das:
ausblenden Quelltext
1:
2:
3:
4:
client: login deruser daspasswort
server: ok
oder
server: error

Und ob du mit Space-delimited-Texten arbeitest (einfacher für Menschen zu lesen; wie im Beispiel oben) oder mit .CommaText, kannst du dir doch auch selbst aussuchen (.CommaText ist vermutlich einfach zu handzuhaben).

der_zaehe hat folgendes geschrieben:
wenn du mir das mit dem buffer kurz erklären könntest (vorausgesetzt natürlich, dass das nicht zu kompliziert oder zu viel zu schreiben ist.

Das Prinzip wird doch in dem von dir genannten Beitrag verwendet (Filetransfer), was soll ich da noch mehr sagen? :wink:

cu
Narses
der_zaehe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 317

WinXP SP2
D6 Pers, D2005 Prof, VS2005
BeitragVerfasst: Do 03.02.05 21:59 
Narses hat folgendes geschrieben:

Das Prinzip wird doch in dem von dir genannten Beitrag verwendet (Filetransfer), was soll ich da noch mehr sagen? :wink:


Um es präziser zu formulieren: Welchen typ von stream muss ich verwenden (ich will ja erstmal keine files übertragen, sondern records) und wie lese ich aus ihm? Bin noch Anfaenger und noch nicht so geübt darin, bei Fragen auf den punkt zu kommen :)

_________________
[inspirationslos]
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Do 03.02.05 22:17 
Moin!

Nochmal, ich rate grundsätzlich vom Versenden von Records ab, egal was drin steht und wozu das da ist. (Ja, ich weiss, dass der Thread genau darauf abzielt; und genau so sicher weiss ich, dass du das Protokoll nicht mehr nimmst, wenn du Records transportieren kannst... :roll: der Mensch an sich ist faul :wink: )

Ob und was du wie programmierst, ist natürlich deine Sache, aber ich denke, für mich macht es keinen Sinn, dir an dieser Stelle weiter zu helfen. Wenn du den Protokoll-Ansatz laufen hast, könnte man sich Weiterem zuwenden. :wink:

Du kannst eine Datei wie in dem Tut beschrieben versenden (da finde ich, muss ich auch nix mehr erklären, dazu ist das Tut ja da), allerdings ist die angewendete Methode nicht kompatibel zu dem Protokoll-Ansatz (jedenfalls nicht so ohne weiteres) auf String-Basis. Ausserdem würde eine Dateiübertragung in der gleichen Session zu einem blockierten Chat führen, ich kann das so nicht empfehlen (-> deshalb der Tipp mit dem zweiten Kanal wie bei FTP; oder die Alternative).

Mit mir geht´s bei einem funktionierenden Protokollparser weiter. Sorry, aber das wird sonst nix... :(

cu
Narses


Zuletzt bearbeitet von Narses am So 06.02.05 13:55, insgesamt 1-mal bearbeitet
der_zaehe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 317

WinXP SP2
D6 Pers, D2005 Prof, VS2005
BeitragVerfasst: Do 03.02.05 22:40 
na dann :)
ich werd mal gucken was sich aus einem protokoll machen lässt und stell das hier rein. wird allerdings ne weile brauchen, weil ich mir erst mal groooße gedanken um die umsetzung machen muss. 8)
aber trotz allem danke, narses! :) wir treffen uns dann an dieser stelle wieder, sobald ich den code fertig hab

_________________
[inspirationslos]
der_zaehe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 317

WinXP SP2
D6 Pers, D2005 Prof, VS2005
BeitragVerfasst: Sa 05.02.05 23:04 
so, ich bin zurück und ich habe code mitgebracht :) !

Die ClientRead - Procedure:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
procedure TForm1.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  TextRcv: TStringList;
  i: Integer;
begin
  TextRcv := TStringList.Create;
  try
    TextRcv := self.Split(Socket.ReceiveText,#1);
    if TextRcv[0] = 'Client:' then
    begin
      //Liste was gemacht werden soll, wenn der Sender Client ist.
      //Client:, !Text, Sender, Text
      if TextRcv[1] = '!Text' then
      begin
        self.SchreibeChat(TextRcv[2],TextRcv[3],TRUE);
      end;
      //...
    end;
    if TextRcv[0] = 'Server:' then
    begin
      //Liste was gemacht werden soll, wenn der Sender Server ist.
      //Server:, ?Benutzername, Begrüßungstext
      if TextRcv[1] = '?Benutzername' then
      begin
        Socket.SendText('Client:'+#1+'!Benutzername'+#1+LabeledEditNick.Text);
        self.SchreibeChat('Server',TextRcv[2],TRUE);
      end;

      //Server:, !Benutzerliste, Kommt/Geht, Benutzername, Benutzer 1,Benutzer 2,...,Benutzer n
      if TextRcv[1] = '!Benutzerliste' then
      begin
        if TextRcv[2] = 'Kommt' then
        begin
          self.SchreibeChat(TextRcv[3],TextRcv[3]+' hat den Chat betreten.',TRUE);
          ListBoxLeute.Clear;
          for i := 4 to TextRcv.Count-1 do
            ListBoxLeute.AddItem(TextRcv[i],ListBoxLeute);
        end;
        if TextRcv[2] = 'Geht' then
        begin
          self.SchreibeChat(TextRcv[3],TextRcv[3]+' hat den Chat verlassen.',TRUE);
          ListBoxLeute.Clear;
          for i := 4 to TextRcv.Count-1 do
            ListBoxLeute.AddItem(TextRcv[i],ListBoxLeute);
          if TextRcv[3] = LabeledEditNick.Text then
          begin
            Client.Close;
            ListBoxLeute.Clear;
            if Server.Active = TRUE then
            begin
              Server.Close;
              BenutzerListe.Free;
            end;
          end;
        end;
      end;
      //...
    end
  finally
    TextRcv.Free;
  end;
end;


der Server:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
procedure TForm1.ServerClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  TextRcv : TStringList;
  i,index : Integer;
begin
  try
    TextRcv := self.Split(Socket.ReceiveText,#1);
    //Client:, !Text, Sender, Text
    if TextRcv[1] = '!Text' then
      try
        for i := 0 to Server.Socket.ActiveConnections-1 do
          if Server.Socket.Connections[i].Connected then
            Server.Socket.Connections[i].SendText(self.SetzeZusammen(TextRcv,#1));
      except
        ShowMessage('Ein Fehler ist aufgetreten.');
      end;
    //Client:, !Benutzername, Nickname
    if TextRcv[1] = '!Benutzername' then
    begin
      BenutzerListe.Add(TextRcv[2]);
      try
        for i := 0 to Server.Socket.ActiveConnections-1 do
          if Server.Socket.Connections[i].Connected then
            Server.Socket.Connections[i].SendText('Server:'+#1+'!Benutzerliste'+#1+'Kommt'+#1+TextRcv[2]+#1+self.SetzeZusammen(BenutzerListe,#1));
      except
        ShowMessage('Ein Fehler ist aufgetreten.');
      end;
    end;
    //Client:, !Trennt, Nickname
    if TextRcv[1] = '!Trennt' then
    begin
      if BenutzerListe.Sorted = FALSE then
        BenutzerListe.Find(TextRcv[2],index);
      BenutzerListe.Exchange(BenutzerListe.Count-1,index);
      BenutzerListe.Delete(BenutzerListe.Count-1);
      BenutzerListe.Sort;
      try
        for i := 0 to Server.Socket.ActiveConnections-1 do
          if Server.Socket.Connections[i].Connected then
            Server.Socket.Connections[i].SendText('Server:'+#1+'!Benutzerliste'+#1+'Geht'+#1+TextRcv[2]+#1+self.SetzeZusammen(BenutzerListe,#1));
      except
        ShowMessage('Ein Fehler ist aufgetreten.');
      end;
    end;
  finally
    TextRcv.Free;
  end;
end;

procedure TForm1.ServerClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  Socket.SendText('Server:'+#1+'?Benutzername'+#1+'Verbunden mit dem ZChat2 - Server '+Socket.LocalHost+' (IP '+Socket.LocalAddress+') Alles Klar, Roger.');
end;

end.


so, dat waren die wesentlichen elemente. Ein wunderschönes Protokoll! :) Muss mich bei Gelegenheit noch loben... :D
Siehst du noch die eine oder andere Verbesserungsmöglichkeit?

Ach ja, noch zur Erläutereung:
"SchreibeChat" fügt dann den Krempel,den man sehen soll, in ein Memo ein (mit Uhrzeit und allem). "Split" zerlegt einen String anhand eines trennzeichens in einzelne string (ist aber net von mir, sondern aus dem FAQ-Bereich von delphi-forum.de geklaut) "SetzeZusammen" ist von mir selber und funktioniert in umgekehrter Richtung.

_________________
[inspirationslos]
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: So 06.02.05 13:52 
Moin!

Na, war doch gar nicht so schwer, oder? :wink:

der_zaehe hat folgendes geschrieben:
Siehst du noch die eine oder andere Verbesserungsmöglichkeit?

Mir ist das hier aufgefallen:
ausblenden Delphi-Quelltext
1:
ListBoxLeute.AddItem(TextRcv[i],ListBoxLeute);					

Das ist sinnlos, IMHO. Vielleicht wolltest du eher sowas machen:
ausblenden Delphi-Quelltext
1:
ListBoxLeute.Items.Add(TextRcv[i]);					


Ansonsten, wenn der Protokollparser läuft und das tut, was du willst (wie gesagt, ist dein Protokoll), was soll ich dann dazu sagen?

cu
Narses

//EDIT: Klammer zu fehlte noch im Code...


Zuletzt bearbeitet von Narses am So 06.02.05 21:31, insgesamt 1-mal bearbeitet
der_zaehe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 317

WinXP SP2
D6 Pers, D2005 Prof, VS2005
BeitragVerfasst: So 06.02.05 20:10 
hab net gewusst, das es auch einfach nur "add" gibt, deshalb hab ich einfach irgendein objekt bei "object" reingeschrieben :nut:
Ich brauchs jetzt zwar nicht mehr, aber könntest du mir jetzt...vielleicht...noch nen Beispiel für das BufferSend/BufferReceive machen? Nicht missverstehen, ich will dich jetzt nicht dazu drängen oder das unbedingt aus dir rausquetschen, aber mich interessiert es irjendwie immer noch :)
Selbst wenn ich es nicht mehr brauch oder verwenden will.

_________________
[inspirationslos]
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: So 06.02.05 21:41 
Moin!

der_zaehe hat folgendes geschrieben:
Beispiel für das BufferSend/BufferReceive machen?

Ehrlichgesagt, hab´s weiter oben schon nicht verstanden, wo da dein Problem liegt... :wink:

Du hast doch dieses Beispiel gelinked, da ist doch das Buffer-basierte Empfangen drin, beim Senden läufts halt genau anders rum. Übrigens, .SendText und .RecieveText sind auch nix anderes als die Bufferfunktionen mit dem Text als Buffer. :wink:

Schau mal in die OH von Delphi zu diesen Befehlen rein, mehr braucht man doch darüber nicht wissen, finde ich. Adresse, Länge, weg damit; umgekehrt: Adresse, wo´s hin soll, Länge der empfangenen Daten, fertig.

Falls du das Versenden von Records trotzdem noch auf der ToDo-Liste hast: :wink: Vorsicht mit Datentypen, die in Delphi als Descriptor abgebildet sind, z.B. "String". Wenn ein Member deines Records ein String ist (Ausnahme: ShortString), dann sind die eigentlichen Daten auf dem Heap, im Speicherbereich des Records findet sich nur der Descriptor... Du könntest das also gar nicht einfach versenden! :shock:

cu
Narses
der_zaehe Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 317

WinXP SP2
D6 Pers, D2005 Prof, VS2005
BeitragVerfasst: So 06.02.05 21:46 
ach, mist.
na egal :lol:

cu

_________________
[inspirationslos]
µaTh
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Mo 28.02.05 11:09 
Hallo Leute,

ich habe auch das gleiche Problem mit dem Record. Ich will die Records auch verschicken und habe keine Lust die auseinander zu basteln, das ist nämlich ein riesiges Recordarray mit verschiedenen Datentypen.

Vielleicht könnt ihr mir trotzdem helfen.

µaTh
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Sa 05.03.05 18:52 
Moin!

Ich wiederhole mich gerne, aber nur begrenzt: :wink:

Man lasse die Finger von dem (binären) Versenden von Records! Wenn ein Element ein String (Ausnahme: ShortString) ist, geht das sowieso nicht. :roll: :arrow: FAQ-Beitrag dazu

Und auch immer wieder gerne: Für die Netzwerk-Kommunikation empfiehlt es sich dringend, ein Protokoll zu entwickeln!

cu
Narses

//EDIT: FAQ-Link ergänzt


Zuletzt bearbeitet von Narses am So 08.04.07 01:03, insgesamt 1-mal bearbeitet
DGL-luke
Hält's aus hier
Beiträge: 4

Win XP Pro, Win XP Home
D7 Pers, D9 Pers
BeitragVerfasst: Sa 07.04.07 21:19 
Hallo,

das ist ja hier wohl (verzeihung) das blödeste, was ich seit längerem gehört habe: Netzwerkverkehr per Zeichenketten!

- fehleranfällig (Encoding? Tippfehler?)
- schlechte leistung (strings matchen... brrr... if cmd = '' then else if cmd = '' then else)
- extremer overhead (255 Kommandos passen in ein einziges Byte. ein String-kommando hat meistens mehr.)

und die nachteile, die für binäres arbeiten angeführt werden:

- keine strings

wie bitte? keine strings? schonmal sowas gesehen:

ausblenden Delphi-Quelltext
1:
2:
3:
len := length(MyString);
MyMemoryStream.Write(len, SizeOf(len));
MyMemoryStream.Write(MyString[1],length(MyString));


Zitat:

- Für die Netzwerk-Kommunikation empfiehlt es sich dringend, ein Protokoll zu entwickeln!


Welches hätten sie denn gerne? TCP/IP? UDP? Alles bereits unterstützt!
Ein oder zwei Record-Deklarationen - gerne mit varientem teil hintendran, dessen Länge mitgegeben wird - sind doch viel besser als ein Protokoll mit strings.

- proprietär

Hä? Buzzword oder was?
Proprietär - Na und? Auch mit Strings wird es nicht gleich DIN/OSI/POSIX/w_ever-konform. Und abwärtskompatibel - naja. Ein oder zwei reservierte felder, fertig. Oder gleich ein Versions-Byte und die Größe offenlassen, bzw. beim Empfänger entsprechend casten.
Und wenns ein Spiel werden soll, wirds sowieso keine "optionalen" Sachen geben, die man mit einem "alten Protokoll" dann einfach weglässt.
Beim Chat ist das sogar denkbar - aber das hab ich ja grad gesagt, wie das geht.

Ich sehe jetzt nichts, wo es noch einen Vorteil gäbe - es sei denn, man will das protokoll human-writable halten. Die Ausrede lass ich gelten.
Beim human-readable siehts schon wieder anders aus - logfiles kann man auch verbose schreiben.

EDIT: Zur Themafrage: Da bräucht ich kurz den prototypen von BufferSend - TServerSocket/TClientSocket hab ich hier grad nicht.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Sa 07.04.07 22:40 
user profile iconDGL-luke hat folgendes geschrieben:
Hallo,

das ist ja hier wohl (verzeihung) das blödeste, was ich seit längerem gehört habe: Netzwerkverkehr per Zeichenketten!

- fehleranfällig (Encoding? Tippfehler?)

Es gibt viele ältere Protokolle, die damit Arbeiten ... Allein zum Versenden deines Beitrags hast Du mindestens eines genutzt ;-) (BTW: Dahinter steckten dann mal eben noch mindestens 5 RFCs: RFC793, RFC822*, RFC1323, RFC1945 und RFC2616

user profile iconDGL-luke hat folgendes geschrieben:
- schlechte leistung (strings matchen... brrr... if cmd = '' then else if cmd = '' then else)
- extremer overhead (255 Kommandos passen in ein einziges Byte. ein String-kommando hat meistens mehr.)

Na und? Nenn mir ein Protokoll, was soviele Befehle braucht? Die meisten Binärprotokolle kapseln auch nur vorgeparste Textprotokolle, wodurch sie nicht effizienter als SGML sind.

user profile iconDGL-luke hat folgendes geschrieben:
und die nachteile, die für binäres arbeiten angeführt werden:

- keine strings

wie bitte? keine strings? schonmal sowas gesehen:

ausblenden Delphi-Quelltext
1:
2:
3:
len := length(MyString);
MyMemoryStream.Write(len, SizeOf(len));
MyMemoryStream.Write(MyString[1],length(MyString));


Wenn Du das aufführst, hast Du Narses nicht verstanden. Keine Strings in Binärprotokollen war ein Hinweis in Richtung verwendung von Strings und ShortStrings, was einige Zusatzaufgaben erforderlich macht. In Textprotokollen ergeben sich Strings nämlich von Haus aus wenn man entsprechende Terminator-Zeichen setzt ;-)

user profile iconDGL-luke hat folgendes geschrieben:
Zitat:

- Für die Netzwerk-Kommunikation empfiehlt es sich dringend, ein Protokoll zu entwickeln!


Welches hätten sie denn gerne? TCP/IP? UDP? Alles bereits unterstützt!


Wikipedia hat folgendes geschrieben:
Ein Protokoll (griech. πρωτόκολλον, prōtókollon, „[den amtlichen Papyrusrollen] vorgeleimtes Blatt“ aus πρώτος, prõtos, „erster“ und κόλλα, kólla, „Klebe, Leim“) ist ein im Voraus und nach bestimmten Regeln definierter Ablauf, Vorgang oder Prozess beziehungsweise die Aufzeichnung eines solchen Prozesses.


Hat also mit TCP\UDP\IP\ICMP\ARP\... auf den ersten Blick nur das gemeinsam, dass alle genannten bestimmte Regeln definieren, nach denen Daten vermittelt werden.

Ein neues Protokoll heißt also auch nix weiter als "Regeln für die Kommunikation" festzulegen. Bitte weiß wovon Du laberst, bevor Du die Luft verpestest! :mahn:

user profile iconDGL-luke hat folgendes geschrieben:
Ein oder zwei Record-Deklarationen - gerne mit varientem teil hintendran, dessen Länge mitgegeben wird - sind doch viel besser als ein Protokoll mit strings.


Von der Effizienz her NEIN und von der Wartbarkeit her auch nicht ... Spätestens wenn Du zwei Anwendungen mit zwei Unterschiedlichen Protokoll-Versionen miteinander labern lässt, wirst Du schnell sehen, wo bei Terminator-Protokollen die großen Vorteile liegen ;-)

user profile iconDGL-luke hat folgendes geschrieben:
- proprietär

Hä? Buzzword oder was?
Proprietär - Na und? Auch mit Strings wird es nicht gleich DIN/OSI/POSIX/w_ever-konform.

Wozu muss etwas irgendwelchen Konformitätskriterien entsprechen? Wenn's nicht ausgereift ist, dann ist's scheiße auch wenn's zwanzigtausen DIN-Konformitätssiegel hat!

Ach ja: POSIX und OSI sind beides nur Frameworks, die einen Rahmen für weitere Entwicklungen geben. D.h. jede Entwicklung, die sich an diesen Rahmen hält, ist dazu konform. Bei DIN kann auch dein Projekt die Regeln festlegen. Wenn ich also genug Geld hätte, könnte ich auch durchaus Intercal als neue DIN für saubere Programmierung erheben und damit BF ablösen.

user profile iconDGL-luke hat folgendes geschrieben:
Und abwärtskompatibel - naja. Ein oder zwei reservierte felder, fertig. Oder gleich ein Versions-Byte und die Größe offenlassen, bzw. beim Empfänger entsprechend casten.

Und aus Versehen mal ein Reserviertes Bit falsch Gesetzt und dein Nachfolger crasht auf Grund eines unbekannten Software-Fehlers ... Wenn dahinter kein Plan steckt kannst'de's auch gleich lassen!

user profile iconDGL-luke hat folgendes geschrieben:
Und wenns ein Spiel werden soll, wirds sowieso keine "optionalen" Sachen geben, die man mit einem "alten Protokoll" dann einfach weglässt.
Beim Chat ist das sogar denkbar - aber das hab ich ja grad gesagt, wie das geht.

Bei einem Spiel gibt es sehr wohl Situationen, wo man mal die Hälfte vom Protokoll nicht unterstützt. Nämlich genau dann, wenn man das Protokoll neben wiederverwendet, um neben Schach auch Dame spielen zu können ...

user profile iconDGL-luke hat folgendes geschrieben:
Ich sehe jetzt nichts, wo es noch einen Vorteil gäbe - es sei denn, man will das protokoll human-writable halten. Die Ausrede lass ich gelten.
Beim human-readable siehts schon wieder anders aus - logfiles kann man auch verbose schreiben.

Dann frag ich mich, warum man UPnP mit einer echten Teilmenge von SGML betreibt... Das Zeug will weder ein Mensch Lesen, geschweige denn Schreiben!

*RFC822 definiert zwar das Text-Format für Emails, findet aber in Abwandlungen auch in zahlreichen anderen Protokollen, speziell RFC 1945 und RFC 2616 seine Anwendung.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
DGL-luke
Hält's aus hier
Beiträge: 4

Win XP Pro, Win XP Home
D7 Pers, D9 Pers
BeitragVerfasst: Sa 07.04.07 22:54 
Hm... ok... viele Leute arbeiten mit Windows, trotzdem sind n paar arge Schnitzer drin.

Zitat:
Und aus Versehen mal ein Reserviertes Bit falsch Gesetzt und dein Nachfolger crasht auf Grund eines unbekannten Software-Fehlers ... Wenn dahinter kein Plan steckt kannst'de's auch gleich lassen!


Öhm... ok... aus versehen mal vertippt, crasht genauso. und wenn kein plan dahintersteckt, kann mans eh gleich lassen.

Der Nachfolger interpretiert das reservierte bit nicht, weil er schon weiß, dass er mit einem "alten" Client redet. So viel zu Plan.
Microsoft sagt da zwar gerne "dummy_xyz wird nicht verwendet und muss 0 sein", aber warum nullen, wenn man eh weiß, dass mans nicht braucht?

Ich seh immernoch nirgends den entscheidenden vorteil von strings. Und wenn du deine Text-Kommandos einfach auf 1..255 abbildest - wo ist der Unterschied, außer weniger Platzverbrauch?
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: So 08.04.07 00:55 
user profile iconDGL-luke hat folgendes geschrieben:
Hm... ok... viele Leute arbeiten mit Windows, trotzdem sind n paar arge Schnitzer drin.

Zitat:
Und aus Versehen mal ein Reserviertes Bit falsch Gesetzt und dein Nachfolger crasht auf Grund eines unbekannten Software-Fehlers ... Wenn dahinter kein Plan steckt kannst'de's auch gleich lassen!


Öhm... ok... aus versehen mal vertippt, crasht genauso. und wenn kein plan dahintersteckt, kann mans eh gleich lassen.

Dann Red mal mit nem Webserver (mach ich übrigens öfters mal) und achte darauf, was passiert, wenn Du dich vertippst.
Korrekt: Der Webserver antwortet Dir verständlich:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
HTTP/1.1 400 Bad Request
Date: Sat, 07 Apr 2007 22:45:05 GMT
Server: Apache/2.0.54 (Linux/SUSE)
Content-Length: 307
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.
</p>
<hr>
<address>Apache/2.0.54 (Linux/SUSE) Server at linux.local Port 80</address>
</body></html>


Und wär der Server durch meinen Tippfehler abgestürzt, wär mir Tino jetzt ziemlich sauer, weil dies die Ausgabe des EE-Servers ist.

user profile iconDGL-luke hat folgendes geschrieben:
Der Nachfolger interpretiert das reservierte bit nicht, weil er schon weiß, dass er mit einem "alten" Client redet. So viel zu Plan.
Microsoft sagt da zwar gerne "dummy_xyz wird nicht verwendet und muss 0 sein", aber warum nullen, wenn man eh weiß, dass mans nicht braucht?

Dann brauch man sich Bits auch nicht zu reservieren ;-) Nein, man setzt das Bit nur in Ausnahmefällen und belegt solche Bits nur mit Funktionen, die nicht interpretiert werden müssen. Wenn man jetzt weiß, dass CleintOld das Bit nie setzen wird, weiß man, dass wenn es mal gesetzt ist und die Protokoll-Version auf nen Alten Client verweist, das Bit durch einen Fehler gesetzt ist.

user profile iconDGL-luke hat folgendes geschrieben:
Ich seh immernoch nirgends den entscheidenden vorteil von strings. Und wenn du deine Text-Kommandos einfach auf 1..255 abbildest - wo ist der Unterschied, außer weniger Platzverbrauch?

Ganz einfach: Man kann um einiges einfacher die Kommunikation debuggen . Außerdem ist die Programmierung des Servers auch bereits ohne einen fertigen Client möglich ...

Es hat alles seine Vorteile. Aber wenn man so einseitig wie Du rangehst, wird man weder von der einen Möglichkeit, noch von der anderen Lösung das Potenzial korrekt einschätzen können.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
DGL-luke
Hält's aus hier
Beiträge: 4

Win XP Pro, Win XP Home
D7 Pers, D9 Pers
BeitragVerfasst: So 08.04.07 19:34 
OK, so kann man mit mir reden. Bisher wurde hier nämlich einseitig rangegangen: "Text-Protokoll hui - Binärprotokoll pfui" hab ich da rausgelesen.

Zu "vertippt": Ein geschlossener Client kann damit auch nix anfangen, höchstens die Meldung "Fehler xxx, bitte Einstellungen überprüfen".
Genau dieselben Rückgaben kann doch auch ein Binärprotokoll liefern. Fehlercode xxx - gerne kann man auch einen informativen String dazuliefern. Warum der ganze Markup-Müll außenrum? Natürlich, HTML ist ein Format um Text zu formatieren, und es ist gut möglich, dass zu testzwecken jemand einfach mal sich per telnet verbindet. Also alles prima.
Das sind trotzdem keine definitiven Argumente gegen Binärprotokolle.

Was sich für welchen Zweck am besten eigent, muss man von Einzelfall zu Einzelfall entscheiden.