Supportato da
*Richiede una versione personalizzata di Indy.
IOCP per Windows è un'API che consente di gestire migliaia di connessioni utilizzando un pool limitato di thread invece di usare un thread per connessione come fa Indy per impostazione predefinita.
Per abilitare IOCP per i Server Indy, vada alla proprietà IOHandlerOptions e selezioni iohIOCP come tipo di IOHandler.
Server.IOHandlerOptions.IOHandlerType := iohIOCP;
Server.IOHandlerOptions.IOCP.IOCPThreads := 0;
Server.IOHandlerOptions.IOCP.WorkOpThreads := 0;
Server.IOHandlerOptions.IOCP.PartialRequestTimeout := 0;
Server.IOHandlerOptions.IOCP.TCPKeepAlive.Enabled := True;
Server.IOHandlerOptions.KeepAliveTimeout := 120;
IOCPThreads sono i thread utilizzati per le richieste asincrone IOCP (operazioni overlapped). Per impostazione predefinita il valore è zero, il che significa che il numero di thread viene calcolato in base al numero di processori (eccetto per Delphi 7 e 2007, dove il numero di thread è impostato a 32 perché la funzione cpucount non è supportata).
WorkOpThreads imposta il numero minimo di thread di lavoro mantenuti pronti per elaborare le richieste, 0 per impostazione predefinita. Un thread IOCP si limita a prelevare un'operazione completata e affida il lavoro a questo pool, quindi non si blocca mai su un client lento. Il pool cresce su richiesta fino a un massimo prefissato ogni volta che tutti i thread di lavoro sono già occupati, quindi non è necessario dimensionarlo in anticipo. Aumentare questo valore solo se si desidera che il pool sia già pronto prima della prima richiesta, evitando così il costo della creazione dei thread durante una raffica iniziale di connessioni.
Modificato nella versione 2026.9.0. In precedenza WorkOpThreads vincolava ogni connessione a uno di questi thread, quindi tutte le richieste di una connessione venivano eseguite sullo stesso thread, e WorkOpRoundRobin decideva come le nuove connessioni venivano distribuite tra di essi. Il vincolo è stato rimosso: una connessione in attesa del resto di una richiesta bloccava tutte le altre connessioni assegnate allo stesso thread e paralizzava il server. Le richieste della stessa connessione possono ora essere eseguite su thread diversi, quindi non si deve più presumere che ciò che viene mantenuto per thread, come una connessione a un database o una cache locale al thread, segua una connessione. WorkOpRoundRobin non esiste più. Rimuovere la proprietà dal proprio codice e, se era stata abilitata nell'Object Inspector, eliminare anche la riga WorkOpRoundRobin dal file .dfm del form, altrimenti il form non viene caricato.
PartialRequestTimeout consente al server di attendere il resto di un corpo di richiesta HTTP di cui conosce già la lunghezza, in millisecondi e 0 per impostazione predefinita, il che lo disabilita. Senza di esso, un corpo di richiesta che non arriva completamente all'interno di un singolo completamento, ad esempio un grande POST inviato in più pacchetti, viene scartato silenziosamente e la connessione viene chiusa senza risposta. L'attesa non viene mai eseguita su un thread IOCP, che gestisce molte connessioni e non deve mai bloccarsi, ma viene eseguita sul pool di thread di lavoro descritto sopra, che cresce su richiesta fino a un massimo prefissato, in modo che un client lento o non responsivo non possa esaurirlo e bloccare le altre connessioni.
TCPKeepAlive consente al sistema operativo di sondare le connessioni inattive e rilevare un peer che è scomparso silenziosamente (disabilitato per impostazione predefinita). Quando TCPKeepAlive.Enabled è impostato su True, il sistema operativo inizia a sondare una connessione dopo che è rimasta inattiva per TCPKeepAlive.Time secondi (60 per impostazione predefinita), ripetendo ogni TCPKeepAlive.Interval secondi (10 per impostazione predefinita) finché il peer non risponde o la connessione non viene interrotta.
KeepAliveTimeout chiude qualsiasi connessione che è rimasta inattiva per un periodo superiore al numero di secondi indicato (0 per impostazione predefinita, il che significa disabilitato). Sono interessate solo le connessioni inattive: una richiesta in fase di lettura o una risposta in fase di scrittura non vengono mai interrotte da questo timeout. Questo è il comportamento più vicino al modo in cui l'IOHandler predefinito a thread per connessione libera una connessione silenziosa, e non dipende dal sistema operativo né da alcuna collaborazione da parte del peer.
L'abilitazione di IOCP per i server windows è consigliata quando è necessario gestire migliaia di connessioni. Se il Suo server gestisce solo un massimo di 100 connessioni concorrenti, può rimanere con il modello a thread Indy predefinito.
Evento OnDisconnect non attivato
IOCP funziona in modo diverso dal gestore IOHandler predefinito di Indy. Con il gestore IOHandler predefinito di Indy, ogni connessione viene eseguita in un thread e questi thread sono sempre attivi, verificando se la connessione è attiva, quindi in caso di disconnessione viene notificata in breve tempo.
IOCP funziona in modo diverso: dispone di un pool di thread che gestisce tutte le connessioni, invece di 1 thread = 1 connessione come fa Indy per impostazione predefinita. Per IOCP, l'unico modo per rilevare se una connessione è ancora attiva è tentare di scrivere sul socket. In caso di errore, significa che la connessione è chiusa. Esistono 3 opzioni per rilevare le disconnessioni:
1. Se si utilizza TsgcWebSocketClient, è possibile abilitarlo nella proprietà Options, CleanDisconnect := True (disabilitato per impostazione predefinita). Se abilitato, prima della disconnessione il client invia un messaggio al server per informarlo della disconnessione, in modo che il server riceva questo messaggio e venga generato l'evento OnDisconnect.
2. È possibile abilitare l'heartbeat sul lato server, ad esempio ogni 60 secondi, in modo che tenti di inviare un ping a tutti i client connessi e, se un client si è disconnesso, verrà chiamato OnDisconnect.
3. È possibile abilitare TCPKeepAlive e/o impostare KeepAliveTimeout nelle IOHandlerOptions del server. Questi consentono al server stesso di rilevare un peer che è diventato silenzioso, ad esempio perché il client è andato in crash o la connessione di rete è caduta senza inviare un messaggio di chiusura, e di chiudere la connessione, senza dipendere dall'invio di alcunché da parte del client.