[SOLVED] Indy: check if client is effectively connected lazarus / 38-Networking and Web Programming ---------------------------------------------------------------------- torbente · 2021-02-28 19:22 Hi everyone Using Lazarus 2.0.10 on windows 8.1 I use the following procedure to periodically check if the client receives a line from the server: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Procedure ReadClientLines();var  linea : string;Beginif not ClientChannel.Connected then exit;try   if ClientChannel.IOHandler.InputBufferIsEmpty then      begin      ClientChannel.IOHandler.CheckForDataOnSource(10);      if ClientChannel.IOHandler.InputBufferIsEmpty then Exit;      end;   While not ClientChannel.IOHandler.InputBufferIsEmpty do      begin    Linea := ClientChannel.IOHandler.ReadLn(IndyTextEncoding_UTF8);      ....      end;Except on E:Exception do   ReportTheError(E.Message);End; But if the internet connection just ends (i turn off the wifi connection to test), the application hangs in this procedure. How i could prevent this? ---------------------------------------------------------------------- krolikbest · 2021-03-01 07:03 e.g. use ping in separate thread ---------------------------------------------------------------------- engkin · 2021-03-01 16:21 I don't know where it hangs in your code, but I'll assume inside the while loop. Simply use the other form of ReadLn that has a timeout parameter. ---------------------------------------------------------------------- Remy Lebeau · 2021-03-01 19:02 Quote from: engkin on March 01, 2021, 05:21:26 pmSimply use the other form of ReadLn that has a timeout parameter. Or, you can set the IOHandler's ReadTimeout property beforehand. And check the IOHandler's ReadLnTimedOut property after calling ReadLn(). ---------------------------------------------------------------------- Remy Lebeau · 2021-03-01 19:11 Quote from: torbente on February 28, 2021, 08:22:41 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i if not ClientChannel.Connected then exit;try   if ClientChannel.IOHandler.InputBufferIsEmpty then      begin      ClientChannel.IOHandler.CheckForDataOnSource(10); Note that Connected() performs a read operation internally (with a 0-second timeout), so calling CheckForDataOnSource() immediately afterwards is a bit redundant.  The InputBuffer will either be empty or not after Connected() returns. Quote from: torbente on February 28, 2021, 08:22:41 pmBut if the internet connection just ends (i turn off the wifi connection to test), the application hangs in this procedure. Makes sense, since an abnormal loss of connection is not reported by the OS in a timely manner (it can take minutes/hours!), so until the OS eventually times out internally and invalidates the connection, Connected() will happily continue to return True, and ReadLn() will happily wait for new data up to the specified timeout (via its optional ATimeout parameter, or the IOHandler's ReadTimeout property - neither of which you appear to be using). Quote from: torbente on February 28, 2021, 08:22:41 pmHow i could prevent this? Just because Connected()/CheckForDataOnSource() report that data has arrived does not guarantee that a complete line is available in the InputBuffer.  You should assign a non-infinite timeout to the ReadLn() operation itself. You might also consider enabling TCP-level keepalives (via ClientChannel.Socket.Binding.SetKeepAliveValues(), for instance) so that the OS can timeout internally sooner rather than later if the connection is lost unexpectedly. ---------------------------------------------------------------------- torbente · 2021-03-15 23:38 Ok, trying to improve the connection. I now included a variable: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ReadTimeOutTime : integer; //set to 50 Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Procedure ReadClientLines();var  linea : string;Beginif not ClientChannel.Connected then exit;try   if ClientChannel.IOHandler.InputBufferIsEmpty then      begin      ClientChannel.IOHandler.CheckForDataOnSource(10);      if ClientChannel.IOHandler.InputBufferIsEmpty then Exit;      end;   While not ClientChannel.IOHandler.InputBufferIsEmpty do      begin    ClientChannel.ReadTimeout:=ReadTimeOutTime ;      Linea := ClientChannel.IOHandler.ReadLn(IndyTextEncoding_UTF8);             ....      end;Except on E:Exception do   ReportTheError(E.Message);End; This helps to keep connection with slow peers, but how i could detect if the readtimeout expired? How is... QuoteOr, you can set the IOHandler's ReadTimeout property beforehand. And check the IOHandler's ReadLnTimedOut property after calling ReadLn(). ... this implemented? QuoteYou might also consider enabling TCP-level keepalives (via ClientChannel.Socket.Binding.SetKeepAliveValues(), for instance) so that the OS can timeout internally sooner rather than later if the connection is lost unexpectedly. The system includes a ping system every 5 seconds to keep connections data updated. ---------------------------------------------------------------------- Remy Lebeau · 2021-03-16 02:43 Quote from: torbente on March 16, 2021, 12:38:50 amI now included a variable: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i ReadTimeOutTime : integer; //set to 50 FYI, you can pass that variable directly to ReadLn(), you don't have to reset the ReadTimeout property every time: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Procedure ReadClientLines();var  linea : string;Begin  if not ClientChannel.Connected then Exit;  try    if ClientChannel.IOHandler.InputBufferIsEmpty then    begin      ClientChannel.IOHandler.CheckForDataOnSource(10);      if ClientChannel.IOHandler.InputBufferIsEmpty then Exit;    end;    repeat      // consider setting the IOHandler.DefStringEncoding beforehand, such as      // at connection open.  No need to pass it in to ReadLn() every time...      //      // ClientChannel.ReadTimeout := ReadTimeOutTime;      Linea := ClientChannel.IOHandler.ReadLn('', ReadTimeOutTime, -1, IndyTextEncoding_UTF8);      if ClientChannel.IOHandler.ReadLnTimedOut then Exit;      // use Linea as needed...    until ClientChannel.IOHandler.InputBufferIsEmpty;  except    on E: Exception do      ReportTheError(E.Message);  end;end; Quote from: torbente on March 16, 2021, 12:38:50 amThis helps to keep connection with slow peers, but how i could detect if the readtimeout expired? By checking the IOHandler.ReadLnTimedOut property, like I said earlier, and demonstrated above. ---------------------------------------------------------------------- torbente · 2021-04-10 21:22 I fixed all issues and now the app is running for days without hang  I will open a new thread for a different answer.