Reputation: 387
I have a 64-bit server application created using Delphi 10.1, and in this app I have a TIdTCPServer
component.
When a client connects, the thread count increases, and when the client disconnects, the thread count is not reducing. This problem occurs on a Windows Server machine. I'm not handling any code in the OnConnect
and OnDisconnect
events. Below is my OnExecute
method:
try
if not AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.InputBuffer.ExtractToBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes) ;
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
IndySleep(50);
end;
IndySleep(5);
except
end;
Shall I use Application.ProcessMessages()
to resolve this issue?
Because of the thread count increases, I need to restart the Server application regularly.
Upvotes: 1
Views: 406
Reputation: 596256
Don't swallow exceptions! Indy uses exceptions to report things like socket disconnects/errors (EIdConnClosedGracefully
, EIdSocketError
, etc). TIdTCPServer
internally handles uncaught exceptions raised by its event handlers to know when to cleanup the threads that manage the accepted sockets. By swallowing exceptions, you are preventing TIdTCPServer
from doing that cleanup properly.
If you need to catch exceptions for whatever reason (cleanup, logging, etc 1), you should re-raise any exception that is derived from EIdException
, at least. Let TIdTCPServer
handle Indy-generated exceptions, especially ones that occur due to socket disconnection.
1: consider using the TIdTCPServer.OnException
event instead for that.
try
if not AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.InputBuffer.ExtractToBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes);
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
IndySleep(50);
end;
IndySleep(5);
except
on E: Exception do
begin
...
if E is EIdException then
raise; // <-- add this!
end;
end;
I would also suggest getting rid of the IndySleep()
calls, too. You don't actually need them, let Indy do the sleeping for you while waiting for new data to arrive:
try
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
// the next call sleeps until data arrives or the specified timeout elapses...
AContext.Connection.IOHandler.CheckForDataOnSource(55);
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then Exit:
end;
AContext.Connection.IOHandler.InputBuffer.ExtractToBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes);
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
except
on E: Exception do
begin
...
if E is EIdException then
raise;
end;
end;
Alternatively, use TIdIOHandler.ReadBytes()
instead of using TIdBuffer.ExtractToBytes()
directly:
try
SetLength(ReceivedIDBytes.PointerMessage.tyTIDBytes, 0);
// the next call sleeps until data arrives or the IOHandler.ReadTimeout elapses...
AContext.Connection.IOHandler.ReadBytes(ReceivedIDBytes.PointerMessage.tyTIDBytes, -1, False);
if Length(ReceivedIDBytes.PointerMessage.tyTIDBytes) > 0 then
begin
ReceivedIDBytes.ClientSocket := AContext.Connection;
MessageProcessorThread.ProcessMessageQueue.Enqueue(ReceivedIDBytes);
end;
except
on E: Exception do
begin
...
if E is EIdException then
raise;
end;
end;
Upvotes: 5