Winsock2 - wątek dla klienta a sposób na rozłączanie nowych po przekroczeniu ustalonego limitu

0

Idea jest taka - mamy serwerek na socketach, obsługujący klientów łączących się telnetem. Łączy się nowy klient - tworzony jest nowy wątek i tam odbywa się komunikacja z owym klientem, niezależnie od reszty. Max dopuszczalna liczba klientów jest stała. Poza tym, każdy z nich, "dostaje" jeden wątek i dostęp do jednego elementu z tablicy obiektów.

Problem pojawia się, gdy łączy się nowy klient, a limit jest już wykorzystany. Na razie rozwiązanie wygląda mniej więcej tak:

listenSck = socket ...;
while(1)
{
	if(0 != dostKl())//jeśli nie przekroczono limitu
	{
		int pierwszeWolnemiejsce = znajdz();//mamy indeks do obiektu nieużywanego przez klienta

		obiekty[pierwszeWolnemiejsce].ustawZajety();//rezerwujemy
		obiekty[pierwszeWolnemiejsce].ustaw(accept(listenSck,NULL,NULL));//socket dla wolnego
		CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)obiekty[pierwszeWolnemiejsce].funkcja, &obiekty[pierwszeWolnemiejsce], 00,0);//nowy wątek
	}
}
 

W przydzielonej funkcji, po zakończeniu zabawy z klientem, zmieniany jest warunek dostępności i obiekt można przydzielic nowemu klientowi.

Jeśli chodzi o działanie - jest ok, jak jest za dużo klientów, ci powyżej limitu wiszą sobie na sockecie (w konsoli nie ma żadnej wiadomości). Jak ktoś się rozłączy - w jego miejsce wskakuje pierwszy z kolejki (zakładam, że socket sobie kolejkuje nowych klientów) i wszystko jest jak trzeba.

Niestety nie do końca jest tak różowo. Po pierwsze - jeśli na takim "wiszącym" kliencie sobie coś wpiszemy, jest to w jakiś sposób przechowywane przez socket. Czyli - jeśli w wątku przesyłam napis do klienta, czekam na dowolny klawisz i go rozłączam, kiedy zwolni się miejsce, to, co wcześniej napisał klient, zostanie mi wrzucone na recv, mimo, że to, co klient wysłał wcześniej, nie jest mi potrzebne.
Po drugie - chciałbym pozbyć się wiszących klientów - jak nie ma miejsc - send(papa) i disconnect. Niby wydaje się to proste:

listenSck = socket ...;
while(1)
{
	if(0 != dostKl())//jeśli nie przekroczono limitu
	{
		int pierwszeWolnemiejsce = znajdz();//mamy indeks do obiektu nieużywanego przez klienta

		obiekty[pierwszeWolnemiejsce].ustawZajety();//rezerwujemy
		obiekty[pierwszeWolnemiejsce].ustaw(accept(listenSck,NULL,NULL));//socket dla wolnego
		CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)obiekty[pierwszeWolnemiejsce].funkcja, &obiekty[pierwszeWolnemiejsce], 00,0);//nowy wątek
	}
	else
	{
		SOCKET sckTempSocket = accept(listenSck, NULL, NULL);//akceptujemy
		send(sckTempSocket, "bye!",strlen("bye!"), 0 );//żegnamy
		closesocket(sckTempSocket);//rozłączamy
	}
}
 

ale jednak nie działa to tak, jak tego oczekuję - mam np. limit 10 klientów, połączy się 10 - jest ok, połączy się 11 - wywali. Z 10 połączonych odejdzie 1 - niby powinna być już możliwość połączenia, ale w praktyce okazuje się, że klient zostaje wywalony - muszę połączyć się jeszcze raz i dopiero wtedy jest ok.
Zakładam, że jak mam 10 klientów, program wskakuje w elsa i czeka na accepcie. Mimo, że ktoś się rozłączył, program nie sprawdza, czy jest wolne miejsce.
Ma ktoś jakiś pomysł?

1
while (true) {
client = accept();
  if (mam_komu_go_dac) {
    rob_na_sockecie(client);
  } else {
    send(client, "papa"); close(client);
  }
}

P.S. masz potencjalny wyścig, w

if(0 != dostKl())//jeśli nie przekroczono limitu
{
int pierwszeWolnemiejsce = znajdz();//mamy indeks do obiektu nieużywanego przez klienta
 
obiekty[pierwszeWolnemiejsce].ustawZajety();//rezerwujemy

Zanim ustawisz zajętość, inny wątek może wykonać dostKl i znajdz - potencjalnie ten sam obiekt.

P.S.2 Formatuj kod! Wiesz - wcięcia i te sprawy ;-)

0

No tak... nie pomyślałem o tym. Tnx.

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