Recent

Author Topic: Indy10 TCPServer (Delphi) -> TCPClient (Lazarus) record sending issue  (Read 12711 times)

swierzbicki

  • Full Member
  • ***
  • Posts: 177
Hello,

I've an issue while sending a record from a Delphi TCP Server to an Lazarus TCP Client.
Lazarus is throwing SIGSEGV exception when I try to read any fields from my record.

I don't know what to do as everything is well working under Delphi. %)
Does anybody know where is my problem ?


Here is the Record structure used to be exchanged between my client and server :

Code: [Select]
type
  TMultiCN =  Record
    Date: Tdatetime;
    Poste: String;
    Pilote1:String;
    Pilote2: String;
    OrdreFrabication: String;
    Evenement: String;
    Piquage:String;
    Point: Double;
    cadencemoyenne: Double;
    cadencemaxi: Double;
    longueur: Double;
  End;

Here is the client code (that works under Delphi but fails with Lazarus)

Code: [Select]
var
  MultiCNData: TMultiCN;
  Buffer: TIdBytes;
begin

  IdTCPClient1.Connect;
  try

    IdTCPClient1.GetResponse('200');

    if IdTCPClient1.SendCmd('OPERATION') <> 100 then
      raise Exception.Create(IdTCPClient1.LastCmdResult.Text.Text);

    IdTCPClient1.IOHandler.ReadBytes(Buffer, SizeOf(MultiCNData));
    BytesToRaw(Buffer, MultiCNData, SizeOf(MultiCNData));

    mmLogs.Lines.Add('-----');
    mmLogs.Lines.Add(DateTimeToStr(MultiCNData.Date)); // All attempt to use the record fields leads to an
    mmLogs.Lines.Add(MultiCNData.Poste);                        // SIGSEGV exception !

  finally
    IdTCPClient1.Disconnect();
    if IdTCPClient1.IOHandler <> nil then
      IdTCPClient1.IOHandler.InputBuffer.Clear;
  end;

Here is the server code (compiled with Delphi)

Code: [Select]
var
  MultiCNData: TMultiCN;
  Buffer: TIdBytes;
  LReply: TIdReplyRFC;
begin
  try

    MultiCNData.Date := Now;
    MultiCNData.Poste := 'PicPic6';
    MultiCNData.Pilote1 := 'Pilote1';
    MultiCNData.Pilote1 := 'Pilote2';
    MultiCNData.OrdreFrabication := '012365';
    MultiCNData.Evenement := 'Démarrage';
    MultiCNData.Piquage := 'Fichier.cnc';
    MultiCNData.Point := 2115;
    MultiCNData.cadencemoyenne := 45.55;
    MultiCNData.cadencemaxi := 78.1;
    MultiCNData.longueur := 1.8;

    LReply := TIdReplyRFC.Create(nil);
    try
      LReply.SetReply(100, 'ready to send you data');
      ASender.Context.Connection.IOHandler.Write(LReply.FormattedReply);
    finally
      FreeAndNil(LReply);
    end;

    Buffer := RawToBytes(MultiCNData, SizeOf(MultiCNData));
    ASender.Context.Connection.IOHandler.Write(Buffer);

  except
    on E: Exception do
    Begin

      ASender.Reply.SetReply(500, E.message);
    end;
  end;
end;

Ps : I'm using the last SVN Indy version / Unicode Delphi version. I've already tried to modify my record structure from string to ansistring fields type...
« Last Edit: August 20, 2014, 06:35:01 pm by swierzbicki »
Lazarus 1.6.2
fpc 3.0.0
wince/win32/win64
delphi berlin

rvk

  • Hero Member
  • *****
  • Posts: 6112
Re: Indy10 TCPServer (Delphi) -> TCPClient (Lazarus) record sending issue
« Reply #1 on: August 20, 2014, 07:00:09 pm »
I don't know what to do as everything is well working under Delphi. %)
...
Here is the Record structure used to be exchanged between my client and server :

Are you using Ansistrings?

What is at the top of your unit?
Do you see a {$H-} or {$H+}?
And are you using {$mode delphi} or {$mode objfpc}?

If you're using a different string-type than Delphi your record-structures won't match.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Indy10 TCPServer (Delphi) -> TCPClient (Lazarus) record sending issue
« Reply #2 on: August 20, 2014, 07:40:45 pm »
1) have you actually seen what rawtobytes does?
2) you do understand that the string data type is what in java is known as a reference type right? which in sort means that the fields Poste, Pilote1, Pilote2, etc are nothing more than pointers to the actual data and those data are not continuous in memory right?
3) which version of delphi are you using? You do know that after D2009 the string datatype is alias for unicodestring while in fpc is still alias for ansistring?

in general, try to convert all string types to short strings ee string[255] instead or even to array[1..4096] of unicodechar/ansichar etc. at least then the rawtobytes function should always work correctly.

keep in mind that from some kind of very good luck you did not have problems so far in the delphi to delphi communication and it is a trap waiting to cut of what ever gets cot in it, so you need to either write your own rawtobytes and bytestoraw routines or change the record something more linear as described above.



Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

swierzbicki

  • Full Member
  • ***
  • Posts: 177
Re: Indy10 TCPServer (Delphi) -> TCPClient (Lazarus) record sending issue
« Reply #3 on: August 21, 2014, 05:55:31 pm »
Hello,

My problem is that I've sent a pointer value. I needed to serialyze my String and Double types.
Remy Lebeau helped me on this.

For those interrested, here is the working code :

Client TCP  code :
Code: [Select]
    var
      MultiCNData: TMultiCN;

      function ReadString: String;
      begin
        Result := IdTCPClient1.IOHandler.ReadString(IdTCPClient1.IOHandler.ReadLongInt, encUTF8);
      end;

      function ReadDouble: Double;
      var
        Tmp: TIdBytes;
      begin
        IdTCPClient1.IOHandler.ReadBytes(Tmp, SizeOf(Double));
        BytesToRaw(Tmp, Result, SizeOf(Double));
      end;

      procedure ReadMultiCN(var Data: TMultiCN);
      begin
        Data.Date := ReadDouble;
        Data.Poste := ReadString;
        Data.Pilote1 := ReadString;
        Data.Pilote2 := ReadString;
        Data.OrdreFrabication := ReadString;
        Data.Evenement := ReadString;
        Data.Piquage := ReadString;
        Data.Point := ReadDouble;
        Data.cadencemoyenne := ReadDouble;
        Data.cadencemaxi := ReadDouble;
        Data.longueur := ReadDouble;
      end;

    begin
      IdTCPClient1.Connect;
      try
        IdTCPClient1.GetResponse(200);

        IdTCPClient1.SendCmd('OPERATION', 100);
        ReadMultiCN(MultiCNData);

        mmLogs.Lines.Add('-----');
        mmLogs.Lines.Add(DateTimeToStr(MultiCNData.Date));
        mmLogs.Lines.Add(MultiCNData.Poste);
      finally
        IdTCPClient1.Disconnect;
        if IdTCPClient1.IOHandler <> nil then
          IdTCPClient1.IOHandler.InputBuffer.Clear;
      end;
   end;

TCP CMD Server code

Code: [Select]
    var
      MultiCNData: TMultiCN;

      procedure SendString(const Value: String);
      var
        Tmp: TIdBytes;
      begin
        Tmp := ToBytes(Value, encUTF8);
        ASender.Context.Connection.IOHandler.Write(Length(Tmp));
        ASender.Context.Connection.IOHandler.Write(Tmp);
      end;

      procedure SendDouble(Value: Double);
      begin
        ASender.Context.Connection.IOHandler.Write(RawToBytes(Value, SizeOf(Double)));
      end;

      procedure SendMultiCN(const Data: TMultiCN);
      begin
        ASender.Context.Connection.IOHandler.WriteBufferOpen;
        try
          SendDouble(Data.Date);
          SendString(Data.Poste);
          SendString(Data.Pilote1);
          SendString(Data.Pilote1);
          SendString(Data.OrdreFrabication);
          SendString(Data.Evenement);
          SendString(Data.Piquage);
          SendDouble(Data.Point);
          SendDouble(Data.cadencemoyenne);
          SendDouble(Data.cadencemaxi);
          SendDouble(Data.longueur);
          ASender.Context.Connection.IOHandler.WriteBufferClose;
        except
          ASender.Context.Connection.IOHandler.WriteBufferCancel;
          raise;
        end;
      end;

    begin
      MultiCNData.Date := Now;
      MultiCNData.Poste := 'PicPic6';
      MultiCNData.Pilote1 := 'Pilote1';
      MultiCNData.Pilote1 := 'Pilote2';
      MultiCNData.OrdreFrabication := '012365';
      MultiCNData.Evenement := 'Démarrage';
      MultiCNData.Piquage := 'Fichier.cnc';
      MultiCNData.Point := 2115;
      MultiCNData.cadencemoyenne := 45.55;
      MultiCNData.cadencemaxi := 78.1;
      MultiCNData.longueur := 1.8;

      ASender.Reply.SetReply(100, 'ready to send you data');
      ASender.SendReply;
      SendMultiCN(MultiCNData);
    end;

Lazarus 1.6.2
fpc 3.0.0
wince/win32/win64
delphi berlin

 

TinyPortal © 2005-2018