Entwickler-Ecke

Internet / Netzwerk - AnsiString mit Indys senden


Schwedenbitter - Mi 07.12.16 13:03
Titel: AnsiString mit Indys senden
Hallo,

zunächst möchte ich mich bei Narses für dessen super Anleitungen [https://www.entwickler-ecke.de/topic_66706.html] bzgl. Netzwerkkommunikation bedanken. Ich nutze eine aufgebohrte Version auf einem Linux-Server. Leider nutzen die Sockets von Borland die VCL, so dass ich eine VM mit Windows brauche.
Ein Ausweg sind die Indys. Ich versuche gerade nach 10 Jahren wieder in das Thema zu kommen. Leider scheitere ich daran, dass es mir mit den Indys irgendwie nicht gelingen will, AnsiStrings (für Header und Daten) "verlustfrei" zu versenden.

Natürlich habe ich die Suche benutzt und habe diverse Dinge gefunden. Leider klappt aber folgender Code bei mir nicht:

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:
Procedure TMainForm.Button1Click(Sender: TObject);
Var
  Command      : TCmdSeq;
Begin
  Command:= TCmdSeq.Create($4711);            // Kommandosequenz erzeugen
  Try
    Memo1.Lines.Append(Dump(Command.Frames));    // Kommando-String anzeigen
    Client.Socket.WriteLn(Command.Frames,      // Kommando senden
      IdGlobal.IndyTextEncoding_8Bit);        // 8 bit = AnsiString ?
  Finally
    Command.Free;                      // Objekt wieder freigeben
  End;
End;

Procedure TMainForm.ServerExecute(AContext: TIdContext);
Var
  BinMessage    : AnsiString;
Begin
  If AContext.Connection.Socket.Readable Then    // Es gibt Daten zum Lesen
  Begin
    BinMessage:= AContext.Connection.Socket.ReadLn(
      IdGlobal.IndyTextEncoding_8Bit);          // 8 bit = AnsiString ?
    Memo1.Lines.Append(
      IntToStr(Length(BinMessage)) + ' Zeichen gelesen: ' + #13#10 +
      Dump(BinMessage));                // Daten in hex-Darstellung
  End;
End;

TCmdSeq arbeitet intern natürlich mit AnsiString und liefert auch das richtige Ergebnis vor dem versenden. Wenn ich das durchlaufen lasse, erhalte ich folgende Ausgabe:

Quelltext
1:
2:
3:
04 00 00 80 01 00 11 47 
8 Zeichen gelesen: 
04 00 00 3F 01 00 11 47


Wie schaffe ich es, dass die Indys meinen AnsiString auch als solches behandeln und nicht "kaputt" machen?

Gruß, Alex


Schwedenbitter - Do 08.12.16 13:33

Ich habe natürlich weiter getestet und dachte schon, ich hätte es geschafft. Leider aber wohl doch nicht. Mit folgendem Code sah es ganz gut aus:

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:
//      IdGlobal.IndyTextEncoding_Default;    = $3F
//      IdGlobal.IndyTextEncoding_8Bit);      = $3F
//      IdGlobal.IndyTextEncoding_ASCII);    = $3F
//      IdGlobal.IndyTextEncoding_UTF16LE);    = zusätzliches Zeichen
//      IdGlobal.IndyTextEncoding_OSDefault);  = $80 klappt nicht ab $0A
//      IdGlobal.IndyTextEncoding_UTF16BE);    = $80 klappt nicht ab $0A
//      IdGlobal.IndyTextEncoding_UTF7);      = $80 klappt nicht ab $0A
//      IdGlobal.IndyTextEncoding_UTF8);      = $80 klappt nicht ab $0A

Var
  T:Word = 0;

Procedure TMainForm.Button1Click(Sender: TObject);
Var
  Command      : TCmdSeq;
Begin
  Command:= TCmdSeq.Create($4711);            // Kommandosequenz erzeugen
  Try
    Command.Token:= T; Inc(T);// ==> zum Testen den Token ändern
    Memo1.Lines.Append(
      IntToStr(Length(Command.Frames)) + ' Zeichen geschrieben: ' + #13#10 +
      Dump(Command.Frames));              // Daten in hex-Darstellung
    Client.Socket.DefStringEncoding:= IdGlobal.IndyTextEncoding_UTF7;
    Client.Socket.WriteLn(Command.Frames);      // Kommando senden
  Finally
    Command.Free;                      // Kommandosequenz freigeben
  End;
End;

Procedure TMainForm.ServerExecute(AContext: TIdContext);
Var
  BinMessage    : AnsiString;
Begin
  If AContext.Connection.Socket.Readable Then    // Es gibt Daten zum Lesen
  Begin
    AContext.Connection.Socket.DefStringEncoding:= Client.Socket.DefStringEncoding;
    BinMessage:= AContext.Connection.Socket.ReadLn;
    Memo1.Lines.Append(
      IntToStr(Length(BinMessage)) + ' Zeichen gelesen: ' + #13#10 +
      Dump(BinMessage) + #13#10 +           // Daten in hex-Darstellung
      '-----------------------------');
  End;
End;

Abfänglich sehen die Ausgaben vielversprechend aus. Aber ab einem Zeichen mit $0A ist das ganze aber nicht mehr brauchbar:

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:
8 Zeichen geschrieben: 
04 00 00 80 01 00 09 00 
8 Zeichen gelesen: 
04 00 00 80 01 00 09 00 
-----------------------------
8 Zeichen geschrieben: 
04 00 00 80 01 00 0A 00 
6 Zeichen gelesen: 
04 00 00 80 01 00 
-----------------------------
8 Zeichen geschrieben: 
04 00 00 80 01 00 0B 00 
1 Zeichen gelesen: 
00 
-----------------------------
8 Zeichen geschrieben: 
04 00 00 80 01 00 0C 00 
8 Zeichen gelesen: 
04 00 00 80 01 00 0B 00 
-----------------------------
8 Zeichen geschrieben: 
04 00 00 80 01 00 0D 00 
8 Zeichen gelesen: 
04 00 00 80 01 00 0C 00
usw...


Offenbar gibt es keine Möglichkeit, Strings in binärer Form mit den Indys zu versenden.

Ich habe dann mein Glück damit versucht:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
Procedure TMainForm.Button1Click(Sender: TObject);
Var
  ...
  Buffer      : TIdBytes;
Begin
  ...
    Buffer:= RawToBytes(Command.Frames, Length(Command.Frames));
    Client.Socket.Write(Buffer);
  ...;
End;
Procedure TMainForm.ServerExecute(AContext: TIdContext);
Var
  Buffer      : TIdBytes;
  ByteCount    : Integer;
  ...
Begin
  ...
    ByteCount:= ??? // <== Wie komme ich da heran?
    AContext.Connection.Socket.ReadBytes(Buffer, ByteCount);
    BytesToRaw(Buffer, BinMessage, ByteCount);
    ...
End;

Allerdings weiß ich nicht, wie ich an die genau Anzahl der übertragenen Bytes gelange. Kann mir dabei jemand helfen?

Gruß, Alex


Delete - Do 08.12.16 18:04

- Nachträglich durch die Entwickler-Ecke gelöscht -