How to track the number of customers with Indy TIdTCPServer

I want to know the number of current client connections to Indy 9 TIdTCPServer (on Delphi 2007)

I can not find a property that gives this.

I tried to increment / decrement the counter on the OnConnect / OnDisconnect server, but the number never decreases when the client disconnects.

Any suggestions?

+4
source share
4 answers

Current active clients are stored in the Threads server property, which is TThreadList . Just lock the list, read its Count property, and then open the list:

 procedure TForm1.Button1Click(Sender: TObject); var NumClients: Integer; begin with IdTCPServer1.Threads.LockList do try NumClients := Count; finally IdTCPServer1.Threads.UnlockList; end; ShowMessage('There are currently ' + IntToStr(NumClients) + ' client(s) connected'); end; 

In Indy 10, the Threads property has been replaced with the Contexts property:

 procedure TForm1.Button1Click(Sender: TObject); var NumClients: Integer; begin with IdTCPServer1.Contexts.LockList do try NumClients := Count; finally IdTCPServer1.Contexts.UnlockList; end; ShowMessage('There are currently ' + IntToStr(NumClients) + ' client(s) connected'); end; 
+9
source

I don’t know why using OnConnect and OnDisconnect will not work for you, but we did this to create a descendant of TIdCustomTCPServer; override the DoConnect and DoDisconnect methods and create and use your own descendant TIdServerContext (a stream descendant that will "serve" the connection).

You tell TIdCustomTCPServer about your own TIdServerContext class:

( Modify Added conditional definitions to show how to make it work for Indy9)

 type // Conditional defines so that we can use the same ancestors as in Indy10 and we // can use the same method signatures for DoConnect and DoDisconnect regardless // of the Indy version. Add other conditional defines as needed. // Note: for INDY9 to be defined, you need to include the appropriate includes // from Indy, or define it in your own include file. {$IFDEF INDY9} TIdContext = TIdPeerThread; TIdServerContext = TIdContext; TIdCustomTCPServer = TIdTCPServer; {$ENDIF} TOurContext = class(TIdServerContext) private FConnectionId: cardinal; public property ConnectionId: cardinal ...; end; ... constructor TOurServer.Create(aOwner: TComponent); begin inherited Create(aOwner); ... {$IFDEF INDY10_UP} ContextClass := TOurContext; {$ELSE} ThreadClass := TOurContext; {$ENDIF} ... end; 

In overriding the DoConnect of our descendant TIdCustomTCPServer, we set the ConnectionID of our context class to a unique value:

 procedure TOurServer.DoConnect(AContext: TIdContext); var OurContext: TOurContextabsolute AContext; begin Assert(AContext is TOurContext); HandleGetNewConnectionID(OurContext, OurContext.FConnectionID); inherited DoConnect(AContext); ... end; 

Our DoDisconnect override clears the ConnectionID:

 procedure TOurServer.DoDisconnect(AContext: TIdContext); var OurContext: TOurContextabsolute AContext; begin Assert(AContext is TOurContext); OurContext.FConnectionID := 0; ... inherited DoDisconnect(AContext); end; 

Now you can get a count of current connections at any time:

 function TOurServer.GetConnectionCount: Integer; var i: Integer; CurrentContext: TOurContext; ContextsList: TList; begin MyLock.BeginRead; try Result := 0; if not Assigned(Contexts) then Exit; ContextsList := Contexts.LockList; try for i := 0 to ContextsList.Count - 1 do begin CurrentContext := ContextsList[i] as TOurContext; if CurrentContext.ConnectionID > 0 then Inc(Result); end; finally Contexts.UnLockList; end; finally MyLock.EndRead; end; end; 
+4
source

How about incrementing / decrementing the counter from OnExecute (or DoExecute if you override this)? This can't go wrong!

If you use InterlockedIncrement and InterlockedDecrement , you don’t even need a critical section to protect the counter.

+3
source

This should work on Indy 9, but it’s pretty outdated right now, and maybe something is broken in your version, try updating to the latest version of Indy 9.

I did a simple test using Indy 10 that works great with simple blocked increment / reduction in OnConnect / OnDisconnect event handlers. This is my code:

 //closes and opens the server, which listens at port 1025, default values for all properties procedure TForm2.Button1Click(Sender: TObject); begin IdTCPServer1.Active := not IdTCPServer1.Active; UpdateUI; end; procedure TForm2.FormCreate(Sender: TObject); begin UpdateUI; end; //Just increment the count and update the UI procedure TForm2.IdTCPServer1Connect(AContext: TIdContext); begin InterlockedIncrement(FClientCount); TThread.Synchronize(nil, UpdateUI); end; //Just decrement the count and update the UI procedure TForm2.IdTCPServer1Disconnect(AContext: TIdContext); begin InterlockedDecrement(FClientCount); TThread.Synchronize(nil, UpdateUI); end; //Simple 'X' reply to any character, A is the "command" to exit procedure TForm2.IdTCPServer1Execute(AContext: TIdContext); begin AContext.Connection.IOHandler.Writeln('Write anything, but A to exit'); while AContext.Connection.IOHandler.ReadByte <> 65 do AContext.Connection.IOHandler.Write('X'); AContext.Connection.IOHandler.Writeln(''); AContext.Connection.IOHandler.Writeln('Good Bye'); AContext.Connection.Disconnect; end; //Label update with server status and count of connected clients procedure TForm2.UpdateUI; begin Label1.Caption := Format('Server is %s, %d clients connected', [ IfThen(IdTCPServer1.Active, 'Open', 'Closed'), FClientCount]); end; 

then by opening a couple of clients using telnet:

3 connected clients

then closing one client

2 connected clients

What is it.

INDY 10 is available for Delphi 2007, my main advice is to upgrade anyway.

+2
source

Source: https://habr.com/ru/post/1346227/


All Articles