That structure is incomplete for what I would have suggested for this kind of situation. See further below.
The OnDisconnect event is not called until the Disconnect() method is called. You really shouldn't be using the OnDisconnect event in this situation, though.
The TIdIOHandler.ReadLn() method does not raise an exception on timeout (see this and this). Instead, it sets the TIdIOHandler.ReadLnTimedOut property to True and returns a blank string, which you are not checking for.
The Connected() method will return True if there is any unread data in the TIdIOHandler.InputBuffer that can continue to satisfy read operations without having to go back to the underlying socket to get more data. Once the InputBuffer is exhausted, only then does Connected() check the socket, and if the socket has been *gracfully* closed, or there is a reading error, THEN it returns False.
Simply shutting off the WiFi does not close the socket connection *gracefully*, so it may take time for the OS to detect the TCP connection is dead and invalidate the socket so read/write operations can start reporting errors. If you find that the OS takes too long to report dead connections, you can enable TCP-level keep-alives on the underlying socket. Or simply use your own timeouts in your code and bail out manually if your timeouts elapse.
Connected() should not be raising an exception. Although Connected() may perform a read operation, it should be ignoring any socket errors on that read. If that is not the case, then please file a bug report. Which version of Indy are you using exactly?
Disconnect() calls Connected() internally if its optional ANotifyPeer parameter is True. When a socket read/write exception occurs, you don't really know the state of the communication anymore, so the only viable thing to do is to just close the connection immediately and not try to exchange any more data. Try calling Disconnect() with its ANotifyPeer parameter set to False (it is True by default).
Because you weren't able to fully disconnect.
You really shouldn't be using Connected() at all. Try something more like this instead:
FClient.ConnectTimeout := 5000;
FClient.ReadTimeout := 1000;
while not Terminated do
begin
try
FClient.Connect;
except
// handle connect error as needed...
for I := 1 to 5 do
begin
if Terminated then Break;
Sleep(1000);
end;
continue;
end;
try
FClient.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
while not Terminated do
begin
FData := FClient.IOHandler.ReadLn;
if (FData = '') and FClient.IOHandler.ReadLnTimedOut then
begin
// handle timeout as needed...
end else begin
// handle data as needed...
end;
end;
FClient.Disconnect;
except
FClient.Disconnect(False);
// handle exception as needed...
end;
end;