Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++]Wiele wątków korzystających z tej samej funkcji.

Ostatnio zmodyfikowano 2013-12-07 23:43
Autor Wiadomość
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
C/C++
#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:
C/C++
#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 ) //Funkcja, która ma być odpalana w wielu wątkach.
{
    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 ) {
        //if(Clients==2) return 1;
        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 ) { //Aby być pewnym, że to klient dołącza a nie ktoś przypadkowy
            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
C/C++
#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.
P-98613
DejaVu
» 2013-12-07 22:07:34
No to fajnie, ale teraz jaki masz problem?
P-98652
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.
P-98656
DejaVu
» 2013-12-07 23:09:26
C/C++
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 :)
P-98658
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ą.
P-98660
« 1 »
  Strona 1 z 1