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
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