Lazarus

Programming => General => Topic started by: torbente on July 12, 2018, 08:53:11 am

Title: [SOLVED] File exchange using indy.
Post by: torbente on July 12, 2018, 08:53:11 am
Looking for info about how to send/receive files using indy 10, i found this article:

https://stackoverflow.com/questions/16871393/need-help-sending-file-with-indy

It is to old so im trying to update the info.

Server:
Code: Pascal  [Select][+][-]
  1. CONST_ArchivoAccData = 'DATA/accsum.dat';
  2. AFileStream := TFileStream.Create(CONST_ArchivoAccData, fmOpenRead + fmShareDenyNone);
  3.       try
  4.       Conexiones[Slot].context.Connection.IOHandler.WriteLn('FILEACCSUM');
  5.       Conexiones[Slot].context.connection.IOHandler.Write(AFileStream);
  6.       OutputText('File AccSum sended');
  7.       finally
  8.       AFileStream.Free;
  9.       end;  

I can see the text 'File sended' and the server runs normally after that.

Client:
Code: Pascal  [Select][+][-]
  1. LLine := ConexionesCliente[Number].IOHandler.ReadLn(IndyTextEncoding_UTF8);
  2.    if LLine = 'FILEACCSUM' then
  3.       begin
  4.       if FileExists(CONST_ArchivoAccData) then DeleteFile(CONST_ArchivoAccData);
  5.       AFileStream := TFileStream.Create(CONST_ArchivoAccData, fmCreate);
  6.       ConexionesCliente[Number].IOHandler.ReadStream(AFileStream);
  7.       AFileStream.Free;

The cliente freezes, the file is created as expected, but with 19.146 Kb of size (expected 1 kb) What im missing? Thank you

Title: Re: File exchange using indy.
Post by: torbente on July 13, 2018, 07:00:14 pm
I finally found the way, just editing this line:

Code: Pascal  [Select][+][-]
  1. Conexiones[Slot].context.connection.IOHandler.Write(AFileStream,0,true);
Title: Re: [SOLVED] File exchange using indy.
Post by: Remy Lebeau on July 13, 2018, 10:47:51 pm
Looking for info about how to send/receive files using indy 10, i found this article:

https://stackoverflow.com/questions/16871393/need-help-sending-file-with-indy

It is to old

Yes, that post was written for Indy 9, not Indy 10.

Code: Pascal  [Select][+][-]
  1. Conexiones[Slot].context.connection.IOHandler.Write(AFileStream);
  2. ...
  3. ConexionesCliente[Number].IOHandler.ReadStream(AFileStream);

You have a mismatch here.  You are using the correct methods, but with the wrong parameters.  By default, TIdIOHandler.Write(TStream) DOES NOT send the stream size, but TIdIOHandler.ReadStream() DOES expect a size to be sent.  This is one of the rare cases where a pair of write/read methods do not compliment each other.

You need to either:

1. set the AWriteByteCount parameter of Write() to True:

 
Code: Pascal  [Select][+][-]
  1.  Conexiones[Slot].Context.Connection.IOHandler.LargeStream := True;
  2.  Conexiones[Slot].Context.Connection.IOHandler.Write(AFileStream, 0, True);
  3.  ...
  4.  ConexionesCliente[Number].IOHandler.LargeStream := True;
  5.  ConexionesCliente[Number].IOHandler.ReadStream(AFileStream);

 LargeStream controls whether the stream size is sent/read as a 32bit or 64bit integer.

2. send/read the stream size explicitly:

 
Code: Pascal  [Select][+][-]
  1.  Conexiones[Slot].Context.Connection.IOHandler.Write(AFileStream.Size);
  2.  Conexiones[Slot].Context.Connection.IOHandler.Write(AFileStream);
  3.  ...
  4.  ConexionesCliente[Number].IOHandler.LargeStream := True;
  5.  ConexionesCliente[Number].IOHandler.ReadStream(AFileStream);

 Or:

 
Code: Pascal  [Select][+][-]
  1.  Conexiones[Slot].Context.Connection.IOHandler.WriteLn(IntToStr(AFileStream.Size));
  2.  Conexiones[Slot].Context.Connection.IOHandler.Write(AFileStream);
  3.  ...
  4.  Size := StrToInt64(ConexionesCliente[Number].IOHandler.ReadLn);
  5.  ConexionesCliente[Number].IOHandler.ReadStream(AFileStream, Size, False);

 Or, however other way you want to send/read the stream size.
TinyPortal © 2005-2018