Wielowątkowy server + wielowątkowy klient

0

Witam wszystkich mam pytanie dotyczące wielowątkowych serverów i klientów podłączających się do nich. Załóżmy że klient ma jednocześnie odbierać wiadomości od servera i jednocześnie można je wysyłać więc tu potrzebne są 2 wątki jeden w którym obsługuje odbieranie a wpisywanie i wysyłanie danych w drugim?

A teraz na temat servera, jeżeli chce go wykonać na zasadzie nieokreślonej z góry liczby maksymalnie podłączonych na raz klientów to czy mogę wykonać to na takiej zasadzie:
Tworzę wektor, na początku nie ma żadnych klientów więc ustawiam funkcję listen na 1 aby mogła nasłuchać na 1 klient, potem w nieskończonej pętli akceptuje nowego klienta accept'em i zwiększam listen na 2 gdy zaakceptuje i tak w kółko?

Pozdrawiam i dziękuję za odpowiedzi.

0

co do serwera robisz tak... tworzysz klasę/strukturę reprezentującą klienta. Nasłuchujesz i gdy jest połączenie tworzysz klienta w osobnym wątku i wrzucasz go do kontenera. Od tej chwili każdy klient podłączony do serwera jest reprezentowany przez obiekt tej klasy/struktury, który podtrzymuje połączenie oraz odbiera/wysyła dane do klienta, którego reprezentuje.

0

ustawiam funkcję listen na 1 aby mogła nasłuchać na 1 klient
Kiedy klient się zgłasza to mija jakiś czas zanim główny proces stworzy osobny wątek dla tego klienta (owszem to kilka milisekund ale jednak) ale co stanie się jeżeli w ciągu tych kilka milisekund zgłoszą się 10 kolejnych klientów? Jeżeli w listen wstawisz 1 to tych 10 zostanie odrzuconych, ale jeżeli będą się zgłaszać jeden po drugim (nie wszyscy naraz) to zostaną obsłużeni wszyscy 11 (mimo że podałeś 1). Ta liczba oznacza ile klientów może czekać w kolejce zanim program zdecyduje co z nimi zrobić.

0

Czyli jak z tym listen? Może po prostu ustawić to na jakąś dużą liczbą np 9000?
I dwa wątki w kliencie to dobry pomysł?

0

Musisz obliczyć ile czasu zajmuje stworzenie nowego wątku aby zacząć tego klienta obsługiwać. Potem sprawdzić jaki przewidujesz ruch, czyli ile klientów w ciągu czasu wyliczonego poprzednio będzie w czasie szczytu. Potem tą ilość klientów na wszelki wypadek pomnożyć przez Pi kwadrat i właśnie tyle wpisać w listen.

0

Okej, mam tylko taki jeden mały problem, mam tkai kod:

 while(true)
	{
	Klient temp;
	SOCKET client = accept(sock,(struct sockaddr *)&ich,&sin_size);
	if (client!= INVALID_SOCKET)
			{
				int ID = wszyscy.size(); //wszyscy to wektor struktur Klient; ID na początku 0 potem 1, 2, 3, 4 itd
				memset(&temp,0,sizeof(Klient)); //zeruje strukture
				temp.Gniazdo = client; //wypełniam
				temp.Identyfikator = ID;
				temp.Nick = "";
				temp.Watek = NULL;
				wszyscy.push_back(temp);//Dodaje
				std::cout << ID << std::endl; //dla testu wypisuje ID przydzielone
				std::cout << inet_ntoa(ich.sin_addr) << std::endl;//IP 
				wszyscy[ID].Watek = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE) Watek,&wszyscy[ID], 0 ,NULL);//Tworzę wątek
				if (wszyscy[ID].Watek == NULL) std::cout << "Blad z watkiem!" << std::endl;
	}
	}

Wątek:

DWORD Watek(LPVOID Dane)
{
	const char* tekst_serwera = "Halo, tu server :D\n\0";
	Klient *temp = (Klient*) Dane;
	send(temp->Gniazdo,tekst_serwera,strlen(tekst_serwera),0);
	std::cout << "Podlaczyl sie klient o ID: " << temp->Identyfikator << std::endl;
	char bufor[500];
	while(true)
	{
```c
		memset(bufor,0,500);
 
	recv(temp->Gniazdo,bufor,500,0);
	std::cout << bufor;
}

}

Problem jest taki, że gdy uruchomię np 2 klienty to server wysyła normalnie do nich wiadomość tekst_servera no i gdy napiszę coś w kliencie który uruchomiłem jako drugi i potem wrócę do 1 klienta to prawdopodobnie coś z wątkami się psuje bo serwer skacze z użyciem CPU do 80% (podobną sytuację miałem gdy robiłem ten sam czat ale na tablicy klientów o rozmiarze 20 i któryś z klientów się rozłączył i nie miałem kodu odpowiadającego za obsłużenie zamkniętego wątku, ale przecież teraz nic nie zamykam a tak się dzieje) i nie wyświetla bufora dla 1 klienta zaś dla 2 działa dobrze tylko że strasznie powoli. Lecz jak po uruchamiam więcej klientów to one dobrze wysyłają i serwer dobrze odbiera dane ale wciąż strasznie muli.
0

Zauważyłem, że ten wątek pierwszy robi tylko 1 receive, a potem jakby wychodził z nieskończonej pętli i dzieje się amba fatima.

0

Ktokolwiek?
Dodatkowe info:
Gdy napiszę coś na tym 1 kliencie to recv zwraca błąd: WSAENOTSOCK czyli jakby socket który tam przekazuje nie był nim >.> Chciałbym również zauważyć, że gdy wywołuje wątek to na samym początku deskryptor jest dobry(wartość typu 128 lub 154) lecz po tym recieve zmienia się w 0 albo coś typu 30299. Przypominam dzieje się to tylko na kliencie uruchomionym jako pierwszy.

0

Zmień pętle w wątku na:

char bufor[500];
int n;
	
while((n = recv(temp->Gniazdo, bufor, 500 - 1, 0)) > 0)
{
	bufor[n] = 0;
	std::cout << bufor;
}
0

O kurde, działa idealnie.
Mógłbyś mi powiedzieć dlaczego teraz działa idealnie?

0

Sorry za double post'a ale to jednak nic nie dało. >>

0

Poprawiłem pętle, bo na pierwszy rzut oka wyglądała na źle skonstruowaną (kręciłaby się bez przerwy, niezależnie od stanu połączenia). Nie wnikałem za bardzo w główny problem.

wszyscy.push_back(temp);//Dodaje


wszyscy[ID].Watek = CreateThread(..., &wszyscy[ID], ...);

Problem jest taki, że wątek dostaje adres z vectora, który (teoretycznie) traci ważność co każde dodanie nowego elementu. Każde następne połączenie będzie powodować to, że wątki wcześniejszych połączeń będą operować na obiektach, które już nie istnieją, a to wiadomo czym się kończy. Zamiast vectora, użyj listy.

if (wszyscy[ID].Watek == NULL) std::cout << "Blad z watkiem!" << std::endl;

I co, nie usuwasz z vectora niezainicjowanego połączenia?

0

Ten if to tylko tak był, ten kod nie jest właśnie dokładny ani nic, potem będzie poprawiany. Na razie chce ogólnie dokonać poprawnie tej komunikacji. Właśnie wczoraj wieczorem chciałem spróbować z listami ale było już późno to poszedłem spać, zaraz spróbuje. Dziękuję Ci za zainteresowanie tematem.

0

Kurde te listy mnie dobijają, jednak zwykłę operatory[] są zaje**iste <3
Jak mam się odwołać do elementu listy [jej_wielkość-1] ?

0
std::list<int> lista;
// dodajesz elementy
std::list<int>::iterator last = lista.end()-1;
0

Dobra to mnie zabija. Mam listę struktur i iterator na nią który też jest typu tej struktury.
std::list<Klient> wszyscy;
std::list<Klient> iterator;
temp.Gniazdo = client;
temp.Identyfikator = wszyscy.size();
temp.Nick = "";
temp.Watek = NULL;
wszyscy.push_back(temp);
iterator = wszyscy.end()-1 i nie mogę się do tego odwołać... Pewnie to jest jakieś maks łatwe ale nigdy nie bawiłem się listami i te iteratywny są dość denerwujące.

0
std::list<Klient> iterator;
std::list<Klient>::iterator iterator;
0

Właśnie skapnąłem się jaki głupi błąd wcześniej zrobiłem teraz mam tak:

Klient to taka struktura:
typedef struct
{
SOCKET Gniazdo;
int Identyfikator;
HANDLE Watek;
std::string Nick;
}Klient;

Robię tak:

std::list<Klient> wszyscy;
std::list<Klient>::iterator teraz;

temp.Gniazdo = client;
temp.Identyfikator = wszyscy.size();
temp.Nick = "";
temp.Watek = NULL;
wszyscy.push_back(temp);	
teraz = wszyscy.end()-1

Nie wiem nie umiem wyciągnąć składników tej struktury, rzuca 13 błędów kompilator. Amba fatima.

0

Już sobie poradziłem, nie wiem dlaczego nie zauważyłem metody back().
Dzięki Wam wszystkim

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.