Obsługiwane przez
*Wymaga sgcWebSockets Enterprise Edition.
EPOLL dla systemu Linux to API umożliwiające obsługę tysięcy połączeń przy użyciu ograniczonej puli wątków zamiast stosowania jednego wątku na połączenie, jak domyślnie działa Indy.
Aby włączyć EPOLL dla serwerów Indy, należy przejść do właściwości IOHandlerOptions i wybrać iohIEPOLL jako typ IOHandler.
Server.IOHandlerOptions.IOHandlerType := iohEPOLL;
Server.IOHandlerOptions.EPOLL.EPOLLThreads := 0;
Server.IOHandlerOptions.EPOLL.WorkOpThreads := 0;
Server.IOHandlerOptions.EPOLL.PartialRequestTimeout := 0;
Server.IOHandlerOptions.EPOLL.TCPKeepAlive.Enabled := True;
Server.IOHandlerOptions.KeepAliveTimeout := 120;
EPOLLThreads to wątki używane do asynchronicznych żądań EPOLL (operacje nakładające się); domyślnie wartość wynosi zero, co oznacza, że liczba wątków jest obliczana na podstawie liczby procesorów (z wyjątkiem Delphi 7 i 2007, gdzie liczba wątków wynosi 32, ponieważ funkcja cpucount nie jest obsługiwana). Liczbę wątków można dostosować ręcznie.
WorkOpThreads określa minimalną liczbę wątków roboczych utrzymywanych w gotowości do przetwarzania żądań, domyślnie 0. Wątek EPOLL jedynie wykrywa, że gniazdo jest gotowe, i przekazuje pracę do tej puli, dzięki czemu nigdy nie zostaje zablokowany przez wolnego klienta. Pula rośnie na żądanie aż do ustalonego maksimum zawsze wtedy, gdy wszystkie wątki robocze są już zajęte, nie trzeba więc ustalać jej rozmiaru z góry. Wartość tę należy zwiększyć tylko wtedy, gdy pula ma być przygotowana jeszcze przed pierwszym żądaniem, co pozwala uniknąć kosztu tworzenia wątków podczas początkowej fali połączeń.
Zmiana w wersji 2026.9.0. WorkOpThreads przypisywał wcześniej każde połączenie na stałe do jednego z tych wątków, przez co wszystkie żądania w ramach danego połączenia były wykonywane w tym samym wątku, a WorkOpRoundRobin decydował o tym, w jaki sposób nowe połączenia są rozdzielane pomiędzy te wątki. Przypisywanie na stałe zostało usunięte: połączenie oczekujące na resztę żądania blokowało wszystkie pozostałe połączenia przypisane do tego samego wątku, co zatrzymywało pracę serwera. Żądania w ramach jednego połączenia mogą teraz być wykonywane w różnych wątkach, dlatego nie wolno już zakładać, że dane przechowywane osobno dla każdego wątku, takie jak połączenie z bazą danych czy pamięć podręczna lokalna dla wątku, podążają za połączeniem. Właściwość WorkOpRoundRobin już nie istnieje. Należy usunąć ją z kodu, a jeśli została włączona w Object Inspector, trzeba również usunąć wiersz WorkOpRoundRobin z pliku .dfm formularza, w przeciwnym razie formularz nie zostanie wczytany.
PartialRequestTimeout pozwala serwerowi poczekać na resztę treści żądania HTTP, której długość jest już znana, w milisekundach, domyślnie 0, co wyłącza tę funkcję. Bez niej treść żądania, która nie napłynie w całości w ramach jednego zdarzenia gotowości, na przykład duże żądanie POST wysłane w kilku pakietach, zostaje po cichu odrzucona, a połączenie zamknięte bez odpowiedzi. Oczekiwanie nigdy nie odbywa się w wątku EPOLL, który obsługuje wiele połączeń i nigdy nie może zostać zablokowany; działa ono w opisanej powyżej puli wątków roboczych, która rośnie na żądanie aż do ustalonego maksimum, dzięki czemu wolny lub nieodpowiadający klient nie może jej wyczerpać i zablokować pozostałych połączeń.
TCPKeepAlive umożliwia systemowi operacyjnemu sondowanie bezczynnych połączeń i wykrywanie sytuacji, gdy druga strona połączenia zniknęła bez powiadomienia (domyślnie wyłączone). Gdy TCPKeepAlive.Enabled jest ustawione na True, system operacyjny zaczyna sondować połączenie po okresie bezczynności określonym przez TCPKeepAlive.Time w sekundach (domyślnie 60), powtarzając sondowanie co TCPKeepAlive.Interval sekund (domyślnie 10), aż druga strona odpowie lub połączenie zostanie zerwane.
KeepAliveTimeout zamyka każde połączenie, które pozostawało bezczynne dłużej niż podana liczba sekund (domyślnie 0, co oznacza wyłączenie tej funkcji). Dotyczy to wyłącznie połączeń bezczynnych. Żądanie, które jest właśnie odczytywane, lub odpowiedź, która jest właśnie zapisywana, nigdy nie zostają przerwane przez ten limit czasu. Jest to rozwiązanie najbardziej zbliżone do sposobu, w jaki domyślny IOHandler oparty na modelu jeden wątek na połączenie zwalnia nieaktywne połączenie, i nie zależy ono ani od systemu operacyjnego, ani od współpracy drugiej strony połączenia.
Włączenie EPOLL dla serwerów Linux jest zalecane, gdy wymagana jest obsługa tysięcy połączeń. Jeśli serwer obsługuje maksymalnie 100 równoczesnych połączeń, można pozostać przy domyślnym modelu wątkowym Indy.
Zdarzenie OnDisconnect nie jest wywoływane
EPOLL działa inaczej niż domyślny IOHandler Indy. Przy domyślnym IOHandler Indy każde połączenie działa w osobnym wątku, a wątki te działają przez cały czas i sprawdzają, czy połączenie jest aktywne, dlatego rozłączenie jest zgłaszane w krótkim czasie.
EPOLL działa inaczej. Istnieje pula wątków obsługująca wszystkie połączenia, zamiast modelu 1 wątek = 1 połączenie stosowanego domyślnie przez Indy. W przypadku EPOLL jedynym sposobem wykrycia, czy połączenie jest nadal aktywne, jest próba zapisu do gniazda sieciowego; błąd oznacza, że połączenie zostało zamknięte. Istnieją 3 opcje wykrywania rozłączeń:
1. Jeśli jest używany komponent TsgcWebSocketClient, można go włączyć we właściwości Options, ustawiając CleanDisconnect := True (domyślnie wyłączone). Po włączeniu, przed rozłączeniem klienta wysyłana jest wiadomość informująca serwer o rozłączeniu, dzięki czemu serwer odbierze tę wiadomość i zostanie wywołane zdarzenie OnDisconnect.
2. Można włączyć funkcję heartbeat po stronie serwera, na przykład co 60 sekund. Serwer będzie wówczas próbował wysyłać ping do wszystkich podłączonych klientów, a w przypadku wykrycia rozłączonego klienta zostanie wywołane zdarzenie OnDisconnect.
3. Można włączyć TCPKeepAlive i/lub ustawić KeepAliveTimeout we właściwości IOHandlerOptions serwera. Pozwalają one samemu serwerowi wykryć drugą stronę połączenia, która przestała odpowiadać, na przykład wskutek awarii klienta lub przerwania połączenia sieciowego bez wysłania komunikatu zamknięcia, i zamknąć takie połączenie, bez polegania na tym, że klient cokolwiek wyśle.
Limit połączeń Linux
Aby zwiększyć liczbę jednocześnie otwartych połączeń, należy użyć następującego polecenia
ulimit -n 10000
Poprzednie polecenie ustawia maksymalną liczbę otwartych deskryptorów plików na 10000