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()).
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.