Search code examples
delphiindyindy10tcpserverrawbytestring

TIdTCPServer/TIdTCPClient: the best way to transfer a RawByteString?


I'm looking for a most fastest (stock market application, extremely time critical) solution for transfer a lot of encrypted RawByteString-data (up to 500 records/s, ) from TIdTCPServer to TIdTCPClient.

What is the best way to do that?

Thanks in advance!

Edit:

In my project I need to use a n'Software library for the encryption of strings. The fastest encryption method returns a RawByteString. Theoretically, I should only set the CodePage for encrypted string and transfer it UTF8 encoded, but all my attempts failed.

So seemed to me the most logical:

Server:

var
  rbs: RawByteString;
begin
  rbs := EncryptString(AInput, DEFAULT_ENCRYPTION_KEY);
  SetCodePage(rbs, 65001, true);
  AContext.Connection.IOHandler.WriteLn(rbs, IndyTextEncoding_UTF8);
  ...
end;

Client:

var
  rbs: string;
  Output: string;
begin
  rbs := IdTCPClient1.IOHandler.ReadLn(IndyTextEncoding_UTF8);
  Output := DecryptString(rbs, DEFAULT_ENCRYPTION_KEY);
  ...
end;

Solution

  • Transferring a binary encrypted RawByteString as a UTF-8 string is just plain wrong, no matter how fast it may be. The best way to transfer binary data with Indy 10 is to use a TIdBytes or TStream instead. The IOHandler has reading/writing methods for both, for example:

    var
      rbs: RawByteString;
    begin
      rbs := EncryptString(AInput, DEFAULT_ENCRYPTION_KEY);
      AContext.Connection.IOHandler.Write(Int32(Length(rbs)));
      AContext.Connection.IOHandler.Write(RawToBytes(PAnsiChar(rbs)^, Length(rbs)));
      ...
    end;
    

    var
      buf: TIdBytes;
      rbs: RawByteString;
      Output: string;
    begin
      IdTCPClient1.IOHandler.ReadBytes(buf, IdTCPClient1.IOHandler.ReadInt32);
      SetLength(rbs, Length(buf));
      BytesToRaw(buf, PAnsiChar(rbs)^, Length(rbs));
      Output := DecryptString(rbs, DEFAULT_ENCRYPTION_KEY);
      ...
    end;
    

    Alternatively:

    var
      rbs: RawByteString;
      strm: TIdMemoryBufferStream;
    begin
      rbs := EncryptString(AInput, DEFAULT_ENCRYPTION_KEY);
      strm := TIdMemoryBufferStream.Create(PAnsiChar(rbs), Length(rbs));
      try
        AContext.Connection.IOHandler.LargeStream := False;
        AContext.Connection.IOHandler.Write(strm, 0, True);
      finally
        strm.Free;
      end;
      ...
    end;
    

    var
      strm: TMemoryStream;
      rbs: RawByteString;
      Output: string;
    begin
      strm := TMemoryStream.Create;
      try
        IdTCPClient1.IOHandler.LargeStream := False;
        IdTCPClient1.IOHandler.ReadStream(strm, -1, False);
        SetLength(rbs, strm.Size);
        Move(strm.Memory^, PAnsiChar(rbs)^, Length(rbs));
      finally
        strm.Free;
      end;
    
      { alternatively:
    
      SetLength(rbs, IdTCPClient1.IOHandler.ReadInt32);
      strm := TIdMemoryBufferStream.Create(PAnsiChar(rbs), Length(rbs));
      try
        IdTCPClient1.IOHandler.ReadStream(strm, Length(rbs), False);
      finally
        strm.Free;
      end;
      }
    
      Output := DecryptString(rbs, DEFAULT_ENCRYPTION_KEY);
      ...
    end;