Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: [RESOLU] Probleme de passage de sf::TcpSocket entre deux thread  (Lu 1932 fois)

0 Membres et 1 Invité sur ce sujet

schaoke

  • Newbie
  • *
  • Messages: 2
    • Voir le profil
Bonjour,

Je développe une petite architecture client serveur et je travailles avec deux thread : AuthListener et AuthWorker.
Le premier accepte les connexions entrantes et vérifie si le message reçu est bien de type "demande de connexion". A partir de la il envoi la socket au deuxième thread qui va faire un traitement sur la base de donnée.
Voici mon code de la classe "écouteur"
#include "AuthListener.h"


AuthListener::AuthListener(int port,AuthWorker* authWorker) : selector(), tcpListener(), port(port), isListening(true), mutexListening()
{
}

void AuthListener::runListening()
{
   
    // lie l'écouteur à un port
    if (tcpListener.listen(400) != sf::Socket::Done)
    {
        // erreur...
       
    }
    selector.add(tcpListener);
    //tant que on ecoute, on boucle pour accepter les nouveaux clients
    while (isListening)
    {
        // socket TCP d'écoute de connexions des sockets clients:
        if (selector.wait(sf::milliseconds(60)))
        {
            if (selector.isReady(tcpListener))
            {
                sf::TcpSocket* socket = new sf::TcpSocket();
                if (tcpListener.accept(*socket) == sf::Socket::Done)
                {
                    std::cout << "nouveau client connecté" << std::endl;

                    clients.push_back(socket);
                    //on ajoute la socket au selector
                    selector.add(*socket);
                }
                else
                {
                    //erreur
                    delete socket;

                }
            }
            //on a pas recu de nouvelles connexions de sockets donc on regarde si on a pas reçus de messages de connexions des sockets TCP connectés
            else
            {
                // The listener socket is not ready, test all other sockets (the clients)
                for (std::list<sf::TcpSocket*>::iterator it = clients.begin(); it != clients.end(); ++it)
                {
                    //std::cout << "test 0" << std::endl;
                    sf::TcpSocket& client = **it;
                    if (selector.isReady(client))
                    {
                        std::cout << "test 2" << std::endl;
                        // The client has sent some data, we can receive it
                        sf::Packet packet;
                        if (client.receive(packet) == sf::Socket::Done)
                        {
                            std::cout << "test 1" << std::endl;
                            //on teste l'opcode du message...
                            //si c'est bien une demande de connexion, on traite sinon on rejette
                            sf::Uint32 opcode;
                            packet >> opcode;
                            if (opcode == AuthCodes::CMSG_LOGIN_DEMAND)
                            {
                                std::cout << "opcode bon" << std::endl;
                                //on envoi la demande à AuthWorker qui va traiter la demande
                                authWorker->appendClient(&client, packet);
                                //on enleve le socket du selector
                                selector.remove(client);
                            }
                           
                        }
                    }
                }
            }
           
        }
       
    }

}
 
Voici mon code de la classe qui traite les données
#include "AuthWorker.h"


AuthWorker::AuthWorker() : isWorking(true)
{
}



void AuthWorker::runWorker()
{
    //on traite les données de la map
    std::string user;
    std::string password;
    sf::Uint32 opcode;
    while (this->isWorking)
    {
        //on parcourt la map pour traiter chaque clients puis on le transfert et on delete la map
        std::map<sf::TcpSocket*, sf::Packet>::iterator pos;
        for (pos = clientsMap.begin(); pos != clientsMap.end(); ++pos)
        {
            //on traite le paquet
            pos->second >>opcode>>user>>password;
            //on ne s'occupe pas de l'opcode car authlistener a deja fait le tri
            //requete sql pour verifier que le compte existe et pour recuperer les infos du compte
            std::cout << user << std::endl;
            std::cout << password << std::endl;
        }

    }
}
void AuthWorker::appendClient(sf::TcpSocket* socket, sf::Packet& paquet)
{
    mutexClients.lock(); // mutex.lock()
    clientsMap.insert(std::pair<sf::TcpSocket*, sf::Packet>(socket, paquet));
    mutexClients.unlock();
}
Et voici le code de la classe serveur (qui est créée dans le main et dont la fonction run() tourne pendant tout le programme.)
#include "Server.h"

Server::Server() : isRunning(true), authWorker(), authListener(400,&authWorker), threadAuthListener(0), threadAuthWorker(0)
{
}
bool Server::run()
{
     
    threadAuthListener = new sf::Thread(&AuthListener::runListening, &authListener);
    threadAuthWorker = new sf::Thread(&AuthWorker::runWorker, &authWorker);
    //on lance le thread pour le authlistener
    threadAuthListener->launch();
    //on lance le thread pour le worker
    threadAuthWorker->launch();
    while (isRunning)
    {

    }
   
    return true;
}

 
Lorsque je tente de me connecter avec un client ( dont voici le code)...
sf::TcpSocket socket;
    sf::Socket::Status status = socket.connect(sf::IpAddress::getLocalAddress(), 400);
    if (status != sf::Socket::Done)
    {
        std::cout << "erreur socket " << std::endl;
    }
    else
    {
        sf::Packet paquet;
        paquet << 0x00 << "user" << "password";
        if (socket.send(paquet) == sf::Socket::Done)
        {
            std::cout << "message envoyée " << std::endl;
        }
    }
Mon serveur plante à la ligne 72 du AuthListener.
Apres avoir affiché
test 1.
opcode bon.
C'est a dire à la ligne
//on envoi la demande à AuthWorker qui va traiter la demande
                                authWorker->appendClient(&client, packet);
Il me rapporte ce rapport de débuggage (je ne vous mets que la partie importante)
- this 0x0000000c {tcpListener={...} selector={m_impl=??? } port=??? ...} AuthListener *
__vfptr <Impossible de lire la mémoire> void * *
- tcpListener {...} sf::TcpListener
+ sf::Socket {m_type=??? m_socket=??? m_isBlocking=??? } sf::Socket
- selector {m_impl=??? } sf::SocketSelector
m_impl <Impossible de lire la mémoire>
port <Impossible de lire la mémoire>
isListening <Impossible de lire la mémoire>
+ mutexListening {m_mutexImpl=??? } sf::Mutex
+ clients { size=??? } std::list<sf::TcpSocket *,std::allocator<sf::TcpSocket *> >
authWorker <Impossible de lire la mémoire>

Alors bien entendu je me dis que j'ai du faire une grosse bourde...Mais honnetement je vois pas très bien.
Car je comprends pas trop pourquoi mon listener fais tout planter alors que il envoit juste des informations au worker. Est ce du à une mauvaise utilisation des mutex?
Pourquoi mon selector n'est plus valide?
J'ai réessayé mon code en enlevant le contenu de appendClient();
et son appel ne fait pas tout planter.
Du coup il me semble que je n'ai pas compris l'utilisation des mutexs..
En passant n'hésitez pas à critiquer mon code et mon utilisation des mutex c'est la première fois que je tente de faire du concurrentiel. ;)

Merci beaucoup pour vos réponses! :D
« Modifié: Août 21, 2014, 07:57:57 pm par schaoke »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : [SFML 2.1] Probleme de passage de sf::TcpSocket entre deux thread
« Réponse #1 le: Août 21, 2014, 11:45:39 am »
Il faudrait voir la pile d'appels donnée par le debugger.
Laurent Gomila - SFML developer

schaoke

  • Newbie
  • *
  • Messages: 2
    • Voir le profil
Re : [SFML 2.1] Probleme de passage de sf::TcpSocket entre deux thread
« Réponse #2 le: Août 21, 2014, 12:18:14 pm »
EDIT : ok en fait j'ai fait une erreur grossiere et j'ai crié à l'erreur alors que j'avais juste oublier d'initialiser un pointeur sur le thread authWorker dans la classe du thread authListener...
« Modifié: Août 21, 2014, 07:57:22 pm par schaoke »