TsgcWebSocketClient › Zdarzenia › OnQueueDrained
Uruchamiane, gdy kolejka wiadomości wychodzących przechodzi ze stanu z wiadomościami do stanu pustego.
property OnQueueDrained: TsgcWSQueueDrainedEvent;
// TsgcWSQueueDrainedEvent = procedure(Connection: TsgcWSConnection) of object
—
Uruchamiane tylko wtedy, gdy kolejkowanie wiadomości jest aktywne, to znaczy gdy QueueOptions.Text.Level, QueueOptions.Binary.Level lub QueueOptions.Ping.Level ma wartość inną niż qmNone. Bez kolejki nie ma czego opróżniać i zdarzenie nigdy nie jest wywoływane w domyślnym trybie qdmTransition.
Procedura obsługi wykonuje się bezpośrednio w wątku połączenia i celowo nie jest przekazywana przez NotifyEvents, w przeciwieństwie do wszystkich pozostałych zdarzeń tego komponentu, więc nie może dotykać interfejsu użytkownika. To odstępstwo jest zamierzone. Cała wartość tego zdarzenia polega na tym, że wykonuje się dokładnie w tym punkcie pętli połączenia, zaraz po opróżnieniu kolejki i przed kolejnym odczytem, gdy gniazdo jest jeszcze bezczynne, dzięki czemu aplikacja może zwolnić kolejną porcję danych bez czekania. Przekazanie go do wątku głównego zniweczyłoby tę korzyść. Każdą aktualizację formularza, siatki czy etykiety aplikacja musi przekazać sama, za pomocą TThread.Queue, TThread.Synchronize lub komunikatu wysłanego do wątku głównego.
Wyjątki zgłoszone wewnątrz procedury obsługi są przechwytywane i pomijane, tak aby opróżnianie kolejki zawsze zostało zakończone. Procedura obsługi, która zawiedzie, robi to po cichu, dlatego opakuj jej treść we własny blok try..except, gdy awaria musi zostać zgłoszona.
Właściwość QueueOptions.DrainedMode określa, kiedy zdarzenie jest wywoływane. Przy qdmTransition (domyślnie) jest wywoływane raz na każde przejście ze stanu niepustego do pustego, jak opisano poniżej. Przy qdmEveryPass jest wywoływane w każdym przebiegu pętli połączenia (mniej więcej co Options.ReadTimeout milisekund), zaraz po wysłaniu kolejek, nawet gdy kolejka była już pusta oraz nawet gdy Text.Level, Binary.Level i Ping.Level mają wartość qmNone, więc nie jest potrzebny sztuczny poziom kolejki. W tym trybie procedura obsługi jest haczykiem dla poszczególnych połączeń w wątku połączenia, na przykład do wysyłania oczekujących danych aplikacji za pomocą WriteData, tak aby każdy zapis do połączenia odbywał się z jego własnego wątku (przy Binary.Level ustawionym na qmNone wywołanie WriteData wewnątrz zdarzenia zapisuje bezpośrednio do gniazda). Podobnie jak w trybie przejścia, wykonuje się bezpośrednio i nie podlega ustawieniu NotifyEvents, więc procedura obsługi musi być szybka i nie może dotykać interfejsu użytkownika. Każde połączenie kopiuje opcje kolejki w chwili nawiązania, więc ustaw DrainedMode przed aktywacją komponentu, połączenia już otwarte zachowują poprzedni tryb.
W trybie qdmTransition zdarzenie jest wywoływane raz na każde przejście ze stanu niepustego do pustego, a nie raz na każdy przebieg pętli połączenia. Nie jest to sygnał, że seria wiadomości się zakończyła. Jeśli opróżnianie nadąża za powolnym producentem, każda pojedyncza wiadomość może wywołać własne zdarzenie, ponieważ każda wiadomość jest wysyłana, zanim kolejna trafi do kolejki. Zdarzenie stwierdza jedynie, że kolejka tego połączenia jest w tej chwili pusta, nic więcej.
Typowym zastosowaniem jest kontrola przepływu. Gdy klient przesyła strumieniowo duże ilości danych, użyj tego zdarzenia, aby zwolnić kolejną porcję, dzięki czemu producent podąża za szybkością gniazda zamiast zapełniać pamięć. Połącz je z właściwością PendingCount klasy TsgcWSConnection, która podaje, ile wiadomości nadal czeka w kolejce tego połączenia, aby zrealizować okno kredytowe zamiast wymiany typu stop-and-wait.
Zarządzany port .NET zgłasza to samo zdarzenie o tym samym znaczeniu. Jedyna różnica dotyczy częstotliwości jego występowania. Opróżnianie kolejki w Delphi wykonuje się raz na przebieg pętli połączenia, czyli co Options.ReadTimeOut milisekund, domyślnie co 10, więc powolny strumyk wiadomości jest łączony w niewiele zdarzeń. Opróżnianie w wersji zarządzanej jest sterowane zdarzeniami i ten sam strumyk może wywołać więcej zdarzeń. Serie wiadomości zachowują się identycznie w obu wersjach.
procedure OnQueueDrained(Connection: TsgcWSConnection);
begin
// runs on the connection thread, do not touch the user interface here
Connection.WriteData(GetNextChunk);
end;
// qdmEveryPass: runs on every pass of the connection loop
oClient.QueueOptions.DrainedMode := qdmEveryPass;
oClient.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;