delphiindyfreertosindy10zynq-ultrascale+

ReadTimeout during IOHandler.ReadBytes()


I am using Delphi 12.1 and Indy 10 on the client side and FreeRTOS 10 (Xilinx ARM53 on Zynq UltraScale) and LwiP on the server side. Only one client/thread is active.

I have the following simplified client code.

constructor TSocketThread.Create(CreateSuspended: Boolean);
begin
  inherited Create(CreateSuspended);
  FClient := TIdTCPClient.Create(nil);  // Create the TCP client instance
  FClient.OnConnected := FClientOnConnected;
  FClient.OnDisconnected := FClientOnDisconnected;
end;

procedure TSocketThread.Execute;
var
  Buffer: TIdBytes;
  RecIntegers: array of UInt32;
  MaxBlockSize: Integer;
begin
  while (not Terminated) do
  begin
    //connect client
    try           
      Synchronize(
      procedure
      begin
          Form_System_Log.MemoSystemLog.Lines.Add(FormatDateTime('hh:nn:ss', Now) + ' - ' + 'Connecting Ethernet');
      end);
      FClient.Host := '192.168.1.10'; // Set the IP address
      FClient.Port := 7; // Set the port number
      FClient.Connect;
    except
      for I := 1 to 5 do//wait 5sec to connect again and give room for a thread termination
      begin
        if Terminated then Exit;
        Sleep(1000);
      end;
      Continue; //try to connect again
    end;
    //start communication with server
    try
      FClient.Socket.ReadTimeout  := 3000;
      MaxBlockSize                := (4096*8 + 1024)*4 + 4;
      try
        while (not Terminated) do
        begin
          //--------------------------------------------------------------------
          FClient.Socket.Write(Generate_Sending_ByteArray(data_to_send));
          if FClient.Socket.CheckForDataOnSource(250) then
          begin
            // Method 1
            SetLength(Buffer, MaxBlockSize);
            FClient.IOHandler.ReadBytes(Buffer, MaxBlockSize, False);
            //Method 2
//            SetLength(Buffer, 0);
//            while (length(Buffer) < MaxBlockSize) do
//            begin
//              FClient.IOHandler.ReadBytes(Buffer, -1, True);
//            end;
           end;           
        end;
      except
        on E: Exception do
        begin
          Synchronize(
          procedure
          begin
              Form_System_Log.MemoSystemLog.Lines.Add(FormatDateTime('hh:nn:ss', Now) + ' - ' + 'Error Ethernet Thread: ' + E.Message);
          end);
        end;
      end;
    finally
      FClient.Disconnect;
      //Terminate;//close this thread
    end;
  end;
end;

If I use method 1 for reading:

SetLength(Buffer, MaxBlockSize);
FClient.IOHandler.ReadBytes(Buffer, MaxBlockSize, False);

I get within 60min app runtime around 10 ReadTimeout exceptions. If I don't terminate the thread, the thread tries to connect the client for ever (client can not reconnect)

If I use method 2 for reading:

SetLength(Buffer, 0);
while (length(Buffer) < MaxBlockSize) do
begin
FClient.IOHandler.ReadBytes(Buffer, -1, True);
end;

I dont get ReadTimeout expetions at all but the thread gets stuck.

Q1: I wonder why, since both read methods should lead to the same results.

Q2: Is there a data/byte limit for the input buffer which could lead to a memory issue and the timeout?

Q3: If I use method 2, I dont get a ReadTimeout exeption but it seems that the ethernet thread freezes in a similar time interval as the occurance of the timeout in method 1, but the thread finishes "normal" after this lag. This lag is sometimes longer than the defined timeout. I wonder why, since no ReadTimeout occurs. Could this be just network lag, but then again, why no timeout?

Q4: I wonder why I have such a high traffic:

since I wait on the client side through:

FClient.Socket.CheckForDataOnSource(250)

and the client sends 4096 bytes and the server sends 135172 bytes.

Apologies for so many questions


Solution

  • Thank you very much Remy for your explanation!

    I checked the communication between the server and the client through Wireshark. All packages were send without errors and the server sends the expected number of bytes (no expections).

    Nevertheless, I somehow found an alternative solution to avoid these timeouts by sending less bytes within one data stream. So the issue was on the serverside. Before, I was sending 135172 bytes at once. Now I send 20484 bytes at once.

    I seems, that the TCPWindow was too long.

    I was using (and still use) the settings recommend here: LwIP Settings