TServerSocket, wątki i 300+ połączeń

0

Witam,

Od jakiegoś czasu tworzę serwer który ma za zadanie odbierać połączenie od klienta i sprawdzać wszystkie dane jakie są do niego wysyłane z danymi w bazie danych. Program napisałem w oparciu o TSockety, ponieważ program jest dość duży opisze w skrócie jak działa.

Utworzyłem własną klasę TThread w której są przechowywane dane połączonego klienta.
W TServerSocket OnConnection dałem tworzenie nowego wątku (przechowywane w array of TMojWatek), kiedy łączy się nowy klient szukam pustego miejsca (nil) lub zwiekszam arraya o 1 tworze wątek i zapisuję do niego wszystkie potrzebne dane. Kiedy klient wysyła dane, odbieram go poprzez OnRead i wysyłam do odpowiedniego wątku (szukam go poprzez sockethandle). Na końcu jest jeszcze OnDisconnect i OnError które usuwają wątek z arraya (ustawiają na nil).

Całość działa poprawnie, dla pojedynczych połączeń, powiedzmy 3-4 poł. na sek. I nawet przy 140 połączeniach program działa poprawnie. Niestety problem zaczyna się gdy łączy się kilkanaście klientów na sek. Robi się "bajzel" i bo kilku sek albo wyrzucane są błędy albo program po prostu się zamyka.

Chciałem użyć threadBlocking tak żeby każde połączenie do serwera było wykonywane niezależnie ale niestety nie znalazłem żadnego arytkułu ani przykładu jak wykorzystać threadblocking oraz moje własne wątki. Wszystko co znalazłem to były tylko ogólne zastosowanie ale 0 konkretów z wykorzystaniem tego we własnych wątkach.

Jeśli ktoś wie jak używać threadBlocking w TServerSocket w połączeniu z własnym wątkiem to bardzo mi to pomoże.

Osobiscie myślałem o czymś takim:

type 
  TMojWatek = class(TThread)
    ClientSocket = ^TServerClientThread;
  { ... reszta deklaracji itp...}
  end;

procedure TForm1.ServerSocket1GetThread(Sender: TObject;
  ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread);
var
  Watek: TMojWatek;
begin
  Watek:=TMojWatek.Create(false);
  Watek.ClientSocket := @SocketThread;
{no właśnie i co dalej?!}
end;

tu się zaczyna problem jak odbierać dane od klienta i jak dalej wykonywać zadania które są w wątku tzn. odczytaj dane - sprawdź w bazie danych - wyślij odpowiedz.

Wszelka pomoc mile widziana.

0

Dla każdego podłączonego klienta nowy wątek robisz? Czy dobrze zrozumiałem?
I to działa?

Generalnie, z tego, co wiem to na jednym procesorze jeśli przekraczasz 16 wątków w aplikacji, to możesz zabić maszynę ;)

Wyjść masz kilka.

1 - dla każdego podłączonego klienta tworzyć osobny wątek - złe wyjście - patrz wyżej
2 - tworzysz wątek dla grupy podłączonych klientów. Tak, żeby nie przekraczać powiedzmy 16 wątków - czy też w zależności od ilości procesorów: ilość*16. Minusem jest dość dużo liczenia i generalnie ciężkie do implementacji. Moim zdaniem bardzo łatwo może się coś wywalić.
3 - Robisz wszystko w jednym wątku. Tworzysz sobie tablicę klasy, która trzyma dane o podłączonych klientach.

I czy dobrze rozumiem, że robisz to na Windowsowych socketach? Po co, skoro są do tego komponenty? Np. TServerSocket i TClientSocket.

Jeśli czasem otrzymujesz złe wiadomości(tzn. sklejone jakby, czy coś), to przed odczytem daj krótkiego sleepa, np. na 100 ms.

0

Owszem dla każdego połączenia tworze nowy wątek i działa tak jak powinno (tak jak tego chce) a jeśli więcej jak 16 wątków zabija procka to mój jest jakiś inny bo w Menadżerze zadań mam ok 700 wątków i 66 procesów które aktualnie działają.

Używam TServerSocket.

Sprawdzę z tym sleepem może coś to da ale nie jestem tego taki pewny. Nadal chciałbym dowiedzieć się jak działa threadblocking w TSeverSocket.

0

pfef? 16 wątków? to stojący mi na biurku Pentium I ( monitor za nisko miałem więc położyłem pod niego desktopa, przydaje się też jako maszyna do pisania ) wytrzyma więcej =D

0
PTwr napisał(a)

pfef? 16 wątków? to stojący mi na biurku Pentium I ( monitor za nisko miałem więc położyłem pod niego desktopa, przydaje się też jako maszyna do pisania ) wytrzyma więcej =D

Mówię o 16 wątkach w JEDNEJ aplikacji, a nie w systemie.
Dziwne mi się to wydaje, bo gdzieś czytałem...hmmm, moment
<juhas przegląda pomoc Delphi>

OK, trochę nadinterpretowałem, ale prosto z pomocy Delphi:

"Keeping track of too many threads consumes CPU time; the recommended limit is 16 active threads per process on single processor systems."
0

kontynuując OT: "recommended limit", poza tym to chyba wskazówka z zeszłego millenium. prawda jest taka, że system utrzyma praktycznie każdą ilość wątków. jeśli większość z nich śpi, to nie jest na nie przełączany kontekst, a zatem tak jakby ich nie było (tak jest w tej sytuacji), poza marnotrawieniem zasobów. dużo aktywnych wątków jest bezsensowne z tej racji, że naraz wykonuje się tyle, ile jest procesorów/rdzeni, więc jeśli masz dwa rdzenie, to każdy aktywny wątek więcej niż dwa to tylko niepotrzebne marnowanie czasu na przełączanie kontekstu. więcej wątków - więcej przełączeń kontekstu per ilość obliczeń w danym wątku. dlatego w celu ograniczenia marnotrawienia mocy obliczeniowej na przełaczenia kontekstu używa się tzw. puli wątków (thread pool).tworzysz tylko tyle wątków, ile jest procesorów, a każdy wątek po zakończeniu przerabiania porcji danych nie jest niszczony, tylko dostaje następną porcję. kiedy dane się skończą, wątki mogą być usypiane. Windows ma specjalne API do puli wątków (http://msdn.microsoft.com/en-us/library/ms686766.aspx - tylko nie wiem, czemu minimum client to Vista, thread pool api jest przynajmniej od w2k).

btw. na moim xp w pracy: system: 71 wątków, svchost - 67, 20, 12, ..., eclipse: 48, winlogon: 24, lsass: 21, firefox: 19. część tej listy to natywne procesy systemu, zakładam, że programiści windows chociaż z grubsza wiedzą, co robią (vide 71 wątków systemu).

0

ok watki watkami ale dalej nie wiem jak polaczyć TServerSocket threadblocking z moim watkiem...

Wstawienie sleepa do OnRead troszke pomogło ale nadal przy ok 200 połączeniach zaczyna robić się "bajzel" :/

1 użytkowników online, w tym zalogowanych: 0, gości: 1