Skera Temat założony przez niniejszego użytkownika |
[C++]Wiele wątków korzystających z tej samej funkcji. » 2013-12-07 18:07:19 Witam. Ucząc się C++ postanowiłem zrobić 2 programy, serwer i klient, korzystając z Socks i wątków. Podczas połączenia się klienta do serwera, serwer stworzyłby wątek na funkcji odbierającej żądania od klienta. Problem w tym, że dla każdego klienta ma to być jedna i ta sama funkcja, a przynajmniej z tego co wywnioskowałem rozłącza poprzedniego klienta. Nie wiem jak to zrobić. Na WinSocku i Wątkowaniu nie znam się, wszelkie informacje i kod, który zmodyfikowałem znalazłem tu: http://cpp0x.pl/kursy/Kurs-WinAPI-C++/Zaawansowane/Winsock/371, a o wątkach tu: http://cpp0x.pl/artykuly/?id=8. Kompilator błędów nie wywala, tylko jeżeli połączy się 2 klientów to sygnały od pierwszego połączonego klienta nie dochodzą. Nagłówek: server.h #ifndef head_h #define head_h #ifndef gSOCKET1 #define gSOCKET1 #include <winsock2.h> #include <windows.h> #endif
class gameClient { char BuforOdbioru[ 32 ]; char BuforOdbioru2[ 32 ]; char BuforWysylu[ 32 ]; char BuforWysylu2[ 32 ]; static int lGraczy; public: char nick[ 15 ]; int id; HANDLE watek; SOCKET polaczenie; gameClient( SOCKET client ) : polaczenie( client ) { memset( BuforWysylu, 0, strlen( BuforWysylu ) ); memset( BuforOdbioru, 0, strlen( BuforOdbioru ) ); lGraczy++; id = lGraczy; } int Wyslij( char * ); int Odbierz(); int Rozlacz(); friend void gOdbieraj( void * ); }; class gSocket { char * IP; int Port; SOCKET mainSocket; char BuforOdbioru[ 32 ]; char BuforWysylu[ 32 ]; int Clients = 0; public: gSocket(); int Host( char *, int ); int Odbieraj(); };
Plik z wątkowaniem: #include <cstdio> #include <cstdlib> #include "server.h" #include <winsock2.h> #include <windows.h> #include <iostream> #include <process.h>
using namespace std;
void gOdbieraj( void * Kto ) { gameClient * Gracz =( gameClient * ) Kto; while( true ) { int Odebrane; Odebrane = Gracz->Odbierz(); if( Odebrane == 1 ) { if( strcmp( Gracz->BuforOdbioru2, "Moj nick" ) == 0 ) { cout << "Otrzymywanie nicku Gracza: " << Gracz->id << endl; Sleep( 500 ); Gracz->Wyslij( "Oke" ); if( Gracz->Odbierz() ) { strcpy( Gracz->nick, Gracz->BuforOdbioru2 ); cout << "Otrzymany nick: " << Gracz->nick << endl; } else { cout << "BLEDY" << endl; } } else { cout << "Nierozpoznane dane: " << Gracz->BuforOdbioru2 << endl; } } if( Odebrane == 3 ) break; } _endthread(); } int gameClient::lGraczy = 0; int gameClient::Wyslij( char * Dane ) { int bytesSend; memset( BuforWysylu, 0, strlen( BuforWysylu ) ); strcpy( BuforWysylu, Dane ); bytesSend = send( polaczenie, BuforWysylu, strlen( BuforWysylu ), 0 ); cout << "Wyslano: " << bytesSend << " bitow" << endl; cout << "||Wyslano: " << BuforWysylu << endl; } int gameClient::Odbierz() { int bytesRecv; memset( BuforOdbioru2, 0, strlen( BuforOdbioru2 ) ); while( true ) { bytesRecv = recv( polaczenie, BuforOdbioru2, 32, 0 ); if( bytesRecv == 0 ) continue; if( bytesRecv == WSAECONNRESET ) { printf( "Connection closed.\n" ); return 0; } if( bytesRecv < 0 ) { printf( "Wystapil blad/Rozlaczono\n" ); return 3; } if( strlen( BuforOdbioru2 ) != bytesRecv ) printf( "**Rozna ilosc znakow**\n" ); BuforOdbioru2[ bytesRecv ] = 0; cout << "Odebrano: " << bytesRecv << " bitow" << endl; cout << "||Odebrano: " << BuforOdbioru2 << endl; return 1; } } gSocket::gSocket() { WSADATA wsaData; int result = WSAStartup( MAKEWORD( 2, 2 ), & wsaData ); if( result != NO_ERROR ) printf( "Initialization error.\n" ); mainSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); if( mainSocket == INVALID_SOCKET ) { printf( "Error creating socket: %ld\n", WSAGetLastError() ); WSACleanup(); return; } } int gSocket::Host( char * ip, int port ) { IP = new char[ strlen( ip ) ]; Port = port; sockaddr_in service; memset( & service, 0, sizeof( service ) ); service.sin_family = AF_INET; service.sin_addr.s_addr = inet_addr( ip ); service.sin_port = htons( Port ); if( bind( mainSocket,( SOCKADDR * ) & service, sizeof( service ) ) == SOCKET_ERROR ) { printf( "bind() failed.\n" ); closesocket( mainSocket ); return 0; } if( listen( mainSocket, 1 ) == SOCKET_ERROR ) printf( "Error listening on socket.\n" ); } int gSocket::Odbieraj() { while( true ) { int wyslane; memset( BuforOdbioru, 0, strlen( BuforOdbioru ) ); SOCKET acceptSocket = SOCKET_ERROR; printf( "Waiting for a client to connect...\n" ); while( acceptSocket == SOCKET_ERROR ) { acceptSocket = accept( mainSocket, NULL, NULL ); } printf( "Client connected.\n" ); recv( acceptSocket, BuforOdbioru, 32, 0 ); if( strcmp( BuforOdbioru, "Dolacz" ) == 0 ) { memset( BuforWysylu, 0, strlen( BuforWysylu ) ); gameClient Gracz( acceptSocket ); strcpy( BuforWysylu, "Podaj nick" ); printf( "Wysylanie zapytania o nick.\n" ); wyslane = send( acceptSocket, BuforWysylu, strlen( BuforWysylu ), 0 ); cout << "Wyslano: " << wyslane << " bitow" << endl; Gracz.watek =( HANDLE ) _beginthread( gOdbieraj, 0,( void * ) & Gracz ); Clients++; } else { printf( "Klient nie podal zapytania o dolaczenie, rozlaczanie\n" ); } } }
No i main #include <iostream> #include <string.h> #include <conio.h> #include "server.h" #include <stdlib.h> #include <iostream> using namespace std;
gSocket gs;
int main() { int ret; gs.Host( "127.0.0.1", 6665 ); ret = gs.Odbieraj(); getch(); }
Co do tego, że kod jest "nieogarnięty" - raz printf(), raz std::cout, raz po angielsku raz polsku to wiem. Wykorzystałem tu przykłady WinSock z tematu wyżej i je odpowiednio przerobiłem. Gdy już rozwiążę wszelkie problemy, to zoptymalizuje cały kod, wywalę wszystko co nie potrzebne. Jest wiele raportowania co i jak gdyż nie wiedziałem co się mogło stać. Prawdę mówiąc to nie jestem sam pewien czy to wątkowanie ciągle tej samej funkcji zawodzi, czy zrobiłem gdzieś błąd z WinSock. Z góry dzięki za pomoc. |
|
DejaVu |
» 2013-12-07 22:07:34 No to fajnie, ale teraz jaki masz problem? |
|
Skera Temat założony przez niniejszego użytkownika |
» 2013-12-07 22:47:00 "tylko jeżeli połączy się 2 klientów to sygnały od pierwszego połączonego klienta nie dochodzą." Jak podłączam się jednym klientem to wszelkie informacje są odbierane, a kiedy podłącze drugiego klienta to informacje z pierwszego przestają być odbierane, a z drugiego są normalnie. |
|
DejaVu |
» 2013-12-07 23:09:26 gameClient Gracz( acceptSocket );
To jest obiekt lokalny, który zginie po wyjściu ze scope-a. Ciesz się, że ta aplikacja się nie wywala, bo w praktyce przekazujesz do wątku wskaźnik na obiekt, który jest chwilę później niszczony. PS. Jak chcesz coś porobić z komunikacją sieciową to polecam Ci się zainteresować biblioteką SFML 2.1. Tutorial jest całkiem przyjazny i klasy do obsługi sieciowej bardzo ładnie opakowują cały gruz, zwany WinSock-iem :) |
|
Skera Temat założony przez niniejszego użytkownika |
» 2013-12-07 23:43:54 Nie wierzę w to... Takie małe głupstwo... Nie mogłem tego zrozumieć przez kilka godzin czemu nie działa, a to jedna zmienna.. Wielkie dzięki! Co do poradnika, zobaczę, ale chcę najpierw same podstawy zrozumieć, czytam właśnie kurs WinSock http://cpp0x.pl/kursy/Kurs-WinSock-C++/271. Jak to przeczytam postaram się zaznajomić z tą biblioteką. |
|
« 1 » |