TsgcWebSocketHTTPServer › Eventi › OnQueueDrained

OnQueueDrained Evento

Si attiva quando la coda in uscita di una connessione WebSocket passa dall'avere messaggi all'essere vuota.

Sintassi

property OnQueueDrained: TsgcWSQueueDrainedEvent;
// TsgcWSQueueDrainedEvent = procedure(Connection: TsgcWSConnection) of object

Valore predefinito

—

Note

Si attiva solo quando l'accodamento dei messaggi è attivo per la connessione interessata, cioè quando QueueOptions.Text.Level, QueueOptions.Binary.Level o QueueOptions.Ping.Level è impostato su un valore diverso da qmNone. Senza una coda non c'è nulla da svuotare e l'evento non viene mai generato nella modalità predefinita qdmTransition. Le richieste HTTP semplici non vengono accodate, quindi solo le connessioni WebSocket lo generano.

Il gestore viene eseguito inline sul thread della connessione e deliberatamente non viene instradato attraverso NotifyEvents, a differenza di tutti gli altri eventi di questo componente, quindi non deve toccare l'interfaccia utente. La deviazione è intenzionale. Tutto il valore dell'evento sta nel fatto che viene eseguito esattamente in quel punto del ciclo della connessione, subito dopo che la coda si è svuotata e prima della lettura successiva, mentre il socket è ancora inattivo, in modo che l'applicazione possa concedere il credito successivo senza attendere. Instradarlo verso il thread principale distruggerebbe questo vantaggio. Qualsiasi aggiornamento di form, griglia o etichetta deve essere instradato dall'applicazione stessa, con TThread.Queue, TThread.Synchronize o un messaggio inviato al thread principale.

Le eccezioni generate all'interno del gestore vengono intercettate e scartate, in modo che lo svuotamento venga sempre completato. Un gestore che fallisce lo fa in silenzio, quindi racchiudere il corpo in un proprio blocco try..except quando un errore deve essere segnalato.

La proprietà QueueOptions.DrainedMode seleziona quando viene generato l'evento. Con qdmTransition (predefinito) si attiva una volta per ogni transizione da coda non vuota a coda vuota, come descritto di seguito. Con qdmEveryPass si attiva a ogni passaggio del ciclo della connessione (circa ogni Options.ReadTimeout millisecondi), subito dopo l'invio delle code, anche quando la coda era già vuota e anche quando Text.Level, Binary.Level e Ping.Level sono tutti qmNone, quindi non serve alcun livello di coda fittizio. In questa modalità il gestore è un hook per connessione sul thread della connessione, ad esempio per inviare dati applicativi in sospeso con WriteData, in modo che ogni scrittura su una connessione avvenga dal suo thread (con Binary.Level impostato su qmNone, WriteData all'interno dell'evento scrive direttamente sul socket). Come nella modalità di transizione, viene eseguito inline e non segue NotifyEvents, quindi il gestore deve essere veloce e non deve toccare l'interfaccia utente. Solo l'IOHandler predefinito (un thread per connessione) dispone di questo ciclo: con iohIOCP e iohEPOLL l'evento non viene mai generato a ogni passaggio. Ogni connessione copia le opzioni della coda quando si connette, quindi impostare DrainedMode prima di attivare il componente: le connessioni già aperte mantengono la modalità precedente.

In modalità qdmTransition l'evento si attiva una volta per ogni transizione da coda non vuota a coda vuota, non una volta per ogni passaggio del ciclo della connessione. Non è un segnale che una raffica è terminata. Se lo svuotamento tiene il passo con un produttore lento, ogni singolo messaggio può generare il proprio evento, perché ciascun messaggio viene scritto prima che venga accodato il successivo. Ciò che l'evento afferma è che la coda di questa connessione è vuota in questo momento, nulla di più.

L'uso tipico è il controllo di flusso. Quando il server trasferisce dati di massa tra client, utilizzare l'evento per comunicare a un client mittente che può inviarne altri. Abbinarlo alla proprietà PendingCount di TsgcWSConnection, che indica quanti messaggi sono ancora accodati per quella connessione, per gestire una finestra di credito invece di uno scambio stop and wait.

Il port gestito .NET genera lo stesso evento con lo stesso significato. L'unica differenza è la frequenza con cui arriva. Lo svuotamento Delphi viene eseguito una volta per ogni passaggio del ciclo della connessione, cioè a distanza di Options.ReadTimeOut millisecondi, 10 per impostazione predefinita, quindi un flusso lento di messaggi viene raggruppato in pochi eventi. Lo svuotamento gestito è guidato dagli eventi e lo stesso flusso lento può generare più eventi. Le raffiche si comportano in modo identico in entrambi i casi.

Esempio


procedure OnQueueDrained(Connection: TsgcWSConnection);
begin
  // runs on the connection thread, do not touch the user interface here
  Connection.WriteData('credit 64');
end;

// qdmEveryPass: runs on every pass of the connection loop
oServer.QueueOptions.DrainedMode := qdmEveryPass;
oServer.QueueOptions.Ping.Level := qmLevel1;

procedure OnQueueDrained(Connection: TsgcWSConnection);
begin
  // runs on the connection thread, do not touch the user interface here
  if Connection.Disconnected then
    exit;
  if HasPendingData then
    Connection.WriteData(GetPendingData);
end;

Torna agli Eventi