Recent

Author Topic: Indy10 question  (Read 232 times)

CraigNZ

  • New Member
  • *
  • Posts: 27
Indy10 question
« on: November 02, 2019, 12:31:18 am »
I have setup PortPeeker as a TCP/IP server to send 'Hello' when it gets a connect request and to echo any subsequent messages.  I have dropped a IdTCPClient component and a IdIOHandlerStack component on the form and then linked the IOHandler to the TCPClient.  After a bit of testing I found it was not necessary to execute a TCPClient.connect as the stack.open seems to do it.

Here is the test code I am using:

      try
        Main_Form.IdIOHandlerStack.Open;
        s1 := Main_Form.IdIOHandlerStack.ReadLn();
        Main_Form.IdIOHandlerStack.WriteLn('Hello World');
        s2 := Main_Form.IdIOHandlerStack.ReadLn();
        Main_Form.IdIOHandlerStack.Close;
      finally
        ShowMessage('received: ' + s1 + ',' + s2);
      end;

When I execute this code the server does indeed get a connect request from the .Open statement and sends back a 'Hello'.  The next ReadLn executes correctly and s1 now has 'Hello'.  I then send a 'Hello World' to the server (the writeln includes CR LF) and indeed the server does receive it with CR LF and then echoes it back.  The next line as a read timeout of 2000 (2 seconds) but is triggered instantly but S2 is empty.  The ShowMessage shows s1 and s2 but s2 is empty.  The server does indicate a recv problem as if the client failed to receive the echo'd string 'Hello World'.

Any idea why this first readln works but not the second one?

Craig

CraigNZ

  • New Member
  • *
  • Posts: 27
Re: Indy10 question
« Reply #1 on: November 02, 2019, 01:11:31 am »
I have also tried removing the IOHandlerstack and doing this instead:

  try
    Main_Form.IdTCPClient.Connect;
    s1 := Main_Form.IdTCPClient.IOHandler.ReadLn();
    Main_Form.IdTCPClient.IOHandler.WriteLn('Hello World');
    s2 := Main_Form.IdTCPClient.IOHandler.ReadLn();
  finally
    ShowMessage('received: ' + s1 + ',' + s2);
  end;

but I get the same results, s2 shows a null string.

Craig

CraigNZ

  • New Member
  • *
  • Posts: 27
Re: Indy10 question
« Reply #2 on: November 02, 2019, 03:31:51 am »
For some reason it is now working.  I made no changes to the code but I did increase the ReadTimeout property from 2000 to 20000 .. that worked.  Then I successively reduced the value and tested at several smaller values, all worked.  Finally ended up back at 2000 and it still worked.  So not sure what happened but everything seems okay now.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 675
    • Lebeau Software
Re: Indy10 question
« Reply #3 on: November 05, 2019, 08:28:51 pm »
I have dropped a IdTCPClient component and a IdIOHandlerStack component on the form and then linked the IOHandler to the TCPClient.

You don't need to link a TIdIOHandlerStack manually unless you are using a proxy.  TIdTCPClient.Connect() will create a default TIdIOHandlerStack for you if no IOHandler is assigned yet.

After a bit of testing I found it was not necessary to execute a TCPClient.connect as the stack.open seems to do it.

TIdTCPClient.Connect() calls TIdIOHandler.Open() internally to make the actual socket connection.  But there is a lot more work that TIdTCPClient.Connect() does before and after calling TIdIOHandler.Open(), so it is not enough to just call TIdIOHandler.Open() directly.  So just don't do it.  Use TIdTCPClient.Connect() instead (and TIdTCPClient.Disconnect() instead of TIdIOHandler.Close()).

Code: [Select]
try
  Main_Form.IdTCPClient.Connect;
  try
    s1 := Main_Form.IdTCPClient.IOHandler.ReadLn();
    Main_Form.IdTCPClient.IOHandler.WriteLn('Hello World');
    s2 := Main_Form.IdTCPClient.IOHandler.ReadLn();
  finally
    Main_Form.IdTCPClient.Disconnect;
  end;
finally
  ShowMessage('received: ' + s1 + ',' + s2);
end;

Any idea why this first readln works but not the second one?

Not without seeing what your server code actually looks like.

I have also tried removing the IOHandlerstack and doing this instead:
...
but I get the same results, s2 shows a null string.

Assuming your server is not actually doing something wrong (which we can't see), another possibility is just typical network lag lasting longer than your ReadTimeout was prepared to allow.

For some reason it is now working.  I made no changes to the code but I did increase the ReadTimeout property from 2000 to 20000 .. that worked.  Then I successively reduced the value and tested at several smaller values, all worked.  Finally ended up back at 2000 and it still worked.  So not sure what happened but everything seems okay now.

Indy's ReadTimeout is essentially a per-byte timeout.  Indy buffers inbound data for you, the ReadTimeout applies when Indy has to go back to the socket connection to read more bytes into its buffer.  So the ReadTimeout means not even 1 new byte arrived during that time period.

So, that means in your initial run, something was delaying/blocking bytes from reaching your client for more than 2 seconds, so TIdIOHandler.ReadLn() gave up and exited (setting the TIdIOHandler.ReadLnTimedOut property to true).  Since you did not get an actual read error, chances are had you called TIdIOHandler.ReadLn() again, it likely would have finished reading the remaining bytes and returned the full line you were expecting.

Unlike most of TIdIOHandler's other reading methods, TIdIOHandler.ReadLn() does not raise an exception on timeout, it sets the TIdIOHandler.ReadLnTimedOut property instead, which you have to check manually.

FYI, Indy's default ReadTimeout is infinite, so you must have manually set it to 2 seconds initially.  I really don't recommend using a timeout value less than approx 10-15 seconds for network traffic, you never know when network hiccups/delays can occur outside of your control.

Same with the TIdTCPClient.ConnectTimeout property.  It is also infinite by default (unless TIdAntiFreeze is used, then the default is 2 minutes instead).  If you set a manual ConnectTimeout, I do not recommend going below approx 5-10 seconds.
« Last Edit: November 05, 2019, 08:53:08 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)