Postanowiłem za jednym zamachem skumać wątki i sockety. Te drugie są zdecydowanie łatwiejsze, i wydaje mi się, że już sobie radzę. No ale co mi po samotnych socketach, jak trzeba zacząć się łączyć i pisać pierwszy komunikator (jak to zwykle w takich przypadkach). W związku z tym zaatakowałem boost::thread tylko że to jest trochę kosmos. No ale nie poddawałem się, i w stopniu podstawowym opanowałem <boost/thread/thread.hpp>
<boost/bind.hpp>
<boost/thread/mutex.hpp>
czyli wszystko co potrzebne aby stworzyć serwer wielowątkowy [diabel]
Oto część kodu, którą udało mi się stworzyć, niestety nie działa do końca jak się spodziewałem:
funkcja obsługująca przychodzących klientów
void hello(char nr)
{
char rcv_msg[100];
char *numer;
int rec;
string adr="Witaj, polaczyles sie z ";
adr.append(inet_ntoa(moj_adres.sin_addr));
adr.append("\nJestes ");
adr+=nr;
adr.append(" podlaczonym uzytkownikiem.");
boost::mutex::scoped_lock lock(o_mutex);
if (send(polaczone[(nr-'0')-1],adr.c_str(),74,0)==-1){
perror("send");
cout<<WSAGetLastError();
lock.unlock();}
lock.unlock();
do{
boost::mutex::scoped_lock lock(i_mutex);
rec=recv(polaczone[(nr-'0')-1],rcv_msg,99,0);
lock.unlock();
if(rec==-1){
perror("recv");
cout<<WSAGetLastError();
ile--;
break;
}
else if (rec==0){
cout<<"\nKlient nr."<<nr<<" zerwal polaczenie.";
ile--;
vector<boost::thread (*)>::iterator i=watki.begin();
advance(i,nr-'0');
watki.erase(i);
vector<SOCKET>::iterator j=polaczone.begin();
advance(j,nr-'0');
polaczone.erase(j);
break;
}
boost::mutex::scoped_lock lock1(o_mutex);
if (send(polaczone[(nr-'0')-1],rcv_msg,99,0)==-1){
perror("send");
cout<<WSAGetLastError();
lock1.unlock();
break;
}
lock1.unlock();
} while(rcv_msg!="exit");
};
funkcja obsługująca przychodzące połączenia i startująca nowe wątki dla nich
void akceptuj()
{
while(1)//główna pętla accept()
{
polaczone.push_back(accept(nasluchujacy, (struct sockaddr *)&ich_adres,
&rozmiar));
if (polaczone[polaczone.size()-1] == -1) {
perror("accept");
cout<<WSAGetLastError();
continue;
}
cout<<"\nGot connection from: "<<inet_ntoa(ich_adres.sin_addr);
cout<<"\nWatek startuje z numerem: "<<polaczone.size();
ile=polaczone.size();
numer=ile+'0';
watki.push_back(threads.create_thread(boost::bind(&hello,numer)));
}
}//akceptuj
w funkcji main (pomijając wszystkie pierdoły związane z uruchamianiem socketów) odpalam wątek główny akceptujący przychodzące połączenia:
//odpalanie socketów itp itd...
cout<<"\nSerwer uruchomiony, oczekuje na polaczenie";
boost::thread glowny(&akceptuj);
//dalej zamykam wątki i sockety
No i teraz problem. Serwer odpala się, czeka sobie na połącznia, gdy przychodzą wyświetla wiadomość że nastąpiło nowe połączenie, wypisuje od kogo (ip) oraz numer wątku, do którego zostało skierowane. Jest to na razie początek, więc serwer po prostu odsyła klientom ich wiadomości. Wszystko jest cacy dopóki jest połączenie jest jedno ;] Jak przychodzi drugie to mutexy dają o sobie znać (a raczej moja mierna wiedza na ich temat [wstyd] ). Niby nic się nie krzaczy, ale wiadomości są dostarczane do klientów sekwencyjnie. tzn gdy są podłączone 2 komputery, to na początku funkcja recv jest zarezerwowana dla tego z niższym numerem wątku, i tak na zmianę, jak 1 wyśle i otrzyma wiadomość, to potem drugi może to zrobić (a 1 musi czekać). Jak widać w kodzie, stworzyłem sobie 2 mutexy, wydawało mi się że starczy ale najwyraźniej się myliłem, albo może zupełnie źle je zastosowałem [???] Dodam jeszcze, że przy rozłączaniu jest ten sam problem, czyli rozłączenie następuje dopiero jak nadejdzie kolej komputera który chce się rozłączyć, wcześniej komenda jakby nie dociera do serwera (albo może dociera ale funkcja send() jest zajęta dla innego wątku). W każdym razie jak już się rozłączą wszystkie maszyny, to tylko druga jest rozłączana poprawnie, pierwsza (ta z niższym nr. wątku) dostaje błąd recv() :| Co ciekawe po tym rozłączeniu serwer też się wyłącza, chociaż pętla while(1) powinna przecież działać cały czas [!!!]
Mam nadzieję że komuś będzie się chciało to czytać i jakoś mi pomożecie, nie wrzucałem całego kodu bo dużo tego mam, ale jak będzie trzeba to wrzucę.