Silniki serwera IOCP (Windows) i EPOLL (Linux) w sgcWebSockets obsługują tysiące połączeń przy pomocy niewielkiej puli wątków zamiast jednego wątku na połączenie, co czyni je właściwym wyborem dla serwerów pod dużym obciążeniem współbieżnym. Do tej pory nie miały jednak sposobu na zauważenie drugiej strony, która ucicha bez pożegnania. Dwie nowe opcje, TCPKeepAlive i KeepAliveTimeout, wypełniają tę lukę.
Cicha druga strona nigdy nie generuje zdarzenia
IOCP i EPOLL są sterowane zdarzeniami: silnik „śpi”, dopóki system operacyjny nie poinformuje go, że gniazdo ma dane, zostało zamknięte lub wystąpił błąd. Działa to dobrze aż do momentu, gdy druga strona zniknie bez wysłania czystego FIN lub RST, na przykład gdy klient ulegnie awarii, NAT lub zapora sieciowa usunie nieaktywne mapowanie, albo trasa routingu po cichu się zmieni. Dla takiego gniazda nigdy nie nadejdzie żadne zdarzenie, więc połączenie pozostaje na serwerze w stanie ESTABLISHED w nieskończoność.
Klasyczny IOHandler typu jeden wątek na połączenie nie ma tego problemu, ponieważ każde połączenie blokuje się na odczycie z limitem czasu, dzięki czemu ciche połączenie zostaje zauważone i zwolnione przy najbliższym przekroczeniu tego limitu. IOCP i EPOLL nie miały odpowiednika takiego mechanizmu, i dokładnie to dodają te dwie nowe opcje.
TCPKeepAlive: niech pilnuje system operacyjny
Po włączeniu TCPKeepAlive sam system operacyjny zaczyna sondować połączenie, gdy pozostaje ono nieaktywne przez Time sekund, powtarzając sondowanie co Interval sekund, aż druga strona odpowie lub połączenie zostanie zerwane. Domyślnie opcja jest wyłączona; poniższe wartości odpowiadają wartościom domyślnym po włączeniu.
Server.IOHandlerOptions.IOHandlerType := iohEPOLL;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Enabled := True;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Time := 60; // seconds idle before probing
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Interval := 10; // seconds between probes
Na serwerze Windows te same trzy właściwości znajdują się pod IOHandlerOptions.IOCP.TCPKeepAlive.
KeepAliveTimeout: limit czasu bezczynności na poziomie aplikacji
KeepAliveTimeout stosuje inne, bardziej bezpośrednie podejście: zamyka każde połączenie, które pozostawało nieaktywne dłużej niż podana liczba sekund, niezależnie od tego, co postanowią sondy keepalive systemu operacyjnego. Jest to rozwiązanie najbliższe temu, jak IOHandler typu jeden wątek na połączenie już teraz zwalnia ciche połączenia, jest domyślnie wyłączone (wartość 0), a dotyczy wyłącznie połączeń rzeczywiście bezczynnych, żądanie w trakcie odczytu lub odpowiedź w trakcie zapisu nigdy nie zostaną przez nie przerwane.
Server.IOHandlerOptions.EPOLL.KeepAliveTimeout := 120; // seconds
// Windows
Server.IOHandlerOptions.IOCP.KeepAliveTimeout := 120;
Ustaw wartość z odpowiednim zapasem powyżej najwolniejszego oczekiwanego żądania lub odpowiedzi, na przykład 120 sekund dla typowego serwera HTTP lub WebSocket, aby rzeczywiście martwe połączenia były szybko usuwane, nigdy nie naruszając tych, które są po prostu wolne.
Trzeci sposób wykrywania rozłączenia
sgcWebSockets oferował już dwa sposoby zauważenia, że druga strona zniknęła: włączenie CleanDisconnect w TsgcWebSocketClient, dzięki czemu poprawnie zachowujący się klient informuje serwer przed odejściem, albo uruchomienie po stronie serwera mechanizmu heartbeat, który w regularnych odstępach wysyła ping do każdego klienta. Oba rozwiązania zależą od współpracy, w pierwszym przypadku od klienta, w drugim od własnego cyklu ping/pong. TCPKeepAlive i KeepAliveTimeout to pierwsza opcja, która niczego takiego nie wymaga: serwer wykrywa martwe połączenie całkowicie samodzielnie.
Dostępność
Obie opcje są już dostępne w sgcWebSockets dla Delphi i C++ Builder od wersji 7 do 13, pod IOHandlerOptions.EPOLL i IOHandlerOptions.IOCP, obok istniejących ustawień EPOLLThreads, IOCPThreads i WorkOpThreads. Są domyślnie wyłączone, więc dla istniejących serwerów nic się nie zmienia, dopóki ich nie włączysz.
Pobierz wersję próbną i przeczytaj pełną dokumentację IOCP i EPOLL na stronie produktu sgcWebSockets.
Masz pytania lub uwagi? Skontaktuj się z nami, odpowie Ci osoba, która napisała ten kod.
