test12345
test12345

Reputation: 387

Thread count increasing when clients connect to TIdTCPServer

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

Answers (1)

Remy Lebeau
Remy Lebeau

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

Related Questions