Howto determine if connection is still alive with Indy?
-
05-07-2019 - |
Question
I use Indy for TCP communication (D2009, Indy 10).
After evaluating a client request, I want to send the answer to the client. I therefore store the TIdContext, like this (pseudocode)
procedure ConnectionManager.OnIncomingRequest (Context : TIdContext);
begin
Task := TTask.Create;
Task.Context := Context;
ThreadPool.AddTask (Task);
end;
procedure ThreadPool.Execute (Task : TTask);
begin
// Perform some computation
Context.Connection.IOHandler.Write ('Response');
end;
But what if the client terminates the connection somewhere between the request and the answer being ready for sending? How can I check if the context is still valid? I tried
if Assigned (Context) and Assigned (Context.Connection) and Context.Connection.Connected then
Context.Connection.IOHandler.Write ('Response');
but it does not help. In some cases the program just hangs and if I pause execution I can see that the current line is the one with the if conditions.
What happens here? How can I avoid trying to send using dead connections?
Solution
Okay, I found a solution. Instead of storing the TIdContext I use the context list provided by TIdTcpServer:
procedure ThreadPool.Execute (Task : TTask);
var
ContextList : TList;
Context : TIdContext;
FoundContext : Boolean;
begin
// Perform some computation
FoundContext := False;
ContextList := FIdTCPServer.Contexts.LockList;
try
for I := 0 to ContextList.Count-1 do
begin
Context := TObject (ContextList [I]) as TIdContext;
if (Context.Connection.Socket.Binding.PeerIP = Task.ClientInfo.IP) and
(Context.Connection.Socket.Binding.PeerPort = Task.ClientInfo.Port) then
begin
FoundContext := True;
Break;
end;
end;
finally
FIdTCPServer.Contexts.UnlockList;
end;
if not FoundContext then
Exit;
// Context is a valid connection, send the answer
end;
That works for me.
OTHER TIPS
If the client closes the connection, the client machine/network card dies or you have some other network problem between you and the client, you might not know about it until the next time you try to write to the connection.
You could use a heartbeat. Occasionally send a message to the client with a short timeout to see if the connection is still valid. This way, you'll know sooner if there has been an unexpected disconnect. You could wrap it in a "CheckConnection" function and call it before sending your response.