Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Porting old Delphi2007 application using TServerSocket....
#24
(09-29-2020, 06:04 PM)BosseB Wrote: I used TIdBytes in the thread because this is purportedly better than string.

For binary data, certainly.

(09-29-2020, 06:04 PM)BosseB Wrote: The old code expects a stream of events each supplying a string type chunk.
The processing part of the event handler adds the new chunk to a client side string buffer and then checks if the ETX has arrived. So there is a packeting mechanism there.

OK, in that case the problem you mentioned earlier (which you didn't actually go into details about) is related to something else.

(09-29-2020, 06:04 PM)BosseB Wrote: If I instead make the read thread wait for a complete message ending with ETX, before firing off the event, then I guess all of the data (potentially rather big) will be supplied in one call. And the ETX will not be part of it, right?

We have already gone over how to deal with STX/ETX handling with Indy.  I'm not going to get back into that.  Go re-read our earlier comments.

(09-29-2020, 06:04 PM)BosseB Wrote: If I do a read with delimiting char in the thread (ReadLn), then I suspect that if the transfer takes some time the timeout will fire in the thread.

The timeout is applied on a per-byte basis, not for the entire function call.  But yes, if the time between individual bytes exceeds the timeout then the whole read operation will fail and exit.

(09-29-2020, 06:04 PM)BosseB Wrote: How can it know that this happened and not send off the data but instead do another read call?

If TIdIOHandler.ReadLn() fails due to timeout, it will return a blank string, and set IOHandler.ReadLnTimedOut=True.  If TIdIOHandler.ReadBytes() fails due to timeout, it will raise an exception.  Either condition should cause you to skip sending data to your event handler.

(09-29-2020, 06:04 PM)BosseB Wrote: I cannot find a version of Read that uses a terminator and TIdBytes as an expanding buffer...

There is currently no version of TIdIOHandler.ReadLn() available for bytes, only for strings.  But it is not hard to write such logic manually in your own code, eg:

Code:
procedure TReadingThread.Execute;
var
  LInputBufferSize,
  LStartPos,
  LTermPos: Integer;
begin
  LStartPos := 0;

  while not Terminated do
  begin
    if FOwner.Connected then  //Do not use FConn.Connected here
    begin
      LInputBufferSize := FOwner.FConn.IOHandler.InputBuffer.Size;

      if (LInputBufferSize > 0) and (LStartPos < LInputBufferSize) then begin
        LTermPos := FOwner.FConn.IOHandler.InputBuffer.IndexOf($03{ETX}, LStartPos);
      end else begin
        LTermPos := -1;
      end;

      if LTermPos = -1 then begin
        if not FOwner.FConn.IOHandler.CheckForDataOnSource(YourTimeoutHere) then
          Exit; // timeout exceeded...
        FOwner.FConn.IOHandler.CheckForDisconnect;
        LStartPos := LInputBufferSize;
        Continue;
      end;

      FOwner.FConn.IOHandler.ReadBytes(FRxData, LTermPos + 1, False);
      LStartPos := 0;

      if Assigned(FOwner.FOnRxData) then
        Synchronize(DoOnRxData);

      SetLength(FRxData, 0);
    end;
  end;
end;

(09-29-2020, 06:04 PM)BosseB Wrote: Or does ReadLn(ETX) not return any data if the terminator has not been seen?

Correct.

(09-29-2020, 06:04 PM)BosseB Wrote: Will this work (with FRxData being a string instead of TIdBytes):

If the data is delimited with ETX, then yes.

(09-29-2020, 06:04 PM)BosseB Wrote: EDIT:
Well, it turns out that using the ETX in socket readln makes the system throw up an exception from within Indy10 with this message:
Quote:Debugger exception notification
Project <name> raised exception class 'EIdReadLnMaxLineLengthExceeded' with message
Max line length exceeded.

in file '.\Core\IdIOHandler.pas' at line 1524

It happens when a logfile was transfered.
It is pretty big (currently 7.6 Mbytes) and was the reason I asked about the maximum size of transfers before...
What is the maximum line length for Indy10?

EDIT2:
Turns out that in Core/IdIOHandler.pas this is specified:
Code:
const
  GRecvBufferSizeDefault = 32 * 1024;
  GSendBufferSizeDefault = 32 * 1024;
  IdMaxLineLengthDefault = 16 * 1024;
  // S.G. 6/4/2004: Maximum number of lines captured
  // S.G. 6/4/2004: Default to "unlimited"
  Id_IOHandler_MaxCapturedLines = -1;
Which means that the tx and rx buffers are each 32K and the max line length for ReadLn is 16K.

Those are just the defaults.  You can change them at runtime as needed, via the IOHandler's public RecvBufferSize, SendBufferSize, and MaxLineLength properties. Or, in the case of MaxLineLength, TIdIOHandler.ReadLn() has an optional AMaxLineLength input parameter that supercedes the TIdIOHandler.MaxLineLength property if set.

(09-29-2020, 06:04 PM)BosseB Wrote: How can one then transfer data that is megabytes in size using an STX/ETX protocol?

You could set MaxLineLength=0 or MaxLineLength=MaxInt, which will then allow you to receive such large strings as far as available memory will allow.  Or, you can set the IOHandler's MaxLineAction=maSplit and deal with the possibility that ReadLn() will then return partial strings when the MaxLineLength is exceeded (which FYI, there is a separate TIdIOHandler.ReadLnSplit() method for that very purpose).

But, I would not recommend using strings for such large data to begin with.

Reply


Messages In This Thread
RE: Porting old Delphi2007 application using TServerSocket.... - by rlebeau - 09-29-2020, 10:13 PM

Forum Jump:


Users browsing this thread: 1 Guest(s)