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

Auteur Sujet: Problème de réception de données côté Client..  (Lu 4378 fois)

0 Membres et 1 Invité sur ce sujet

Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Problème de réception de données côté Client..
« le: Juin 29, 2017, 10:13:42 pm »
Salut à tous !

Alors voilà, je viens vous voir car j'ai un soucis particulièrement agaçant et je n'arrive absolument pas à en identifier la cause, en effet, lorsque j'envoi une information au serveur depuis mon Client, elle arrive parfaitement à destination.

Je procède de la sorte :

if (structData.xPos != m_mainPlayer.getPosition().x)
{
structData.xPos = m_mainPlayer.getPosition().x;
sf::Packet sendPacket;
sendPacket << DATA::XPOS << structData.xPos;
m_socket.send(sendPacket);
}

Le serveur reçoit parfaitement ma variable " structData.xPos " et bien entendu, grâce à l'enum DATA::XPOS préfigurant dans le packet, il identifie clairement à quoi correspond cette donnée.

Je réceptionne le packet comme suit :



    for (UINT i = 0 ; i < Clients.size() ; i++)
    {
        if (Clients[i].getIdNumber() != 0)
        {
            if (m_socketSelector.isReady(*Clients[i].getSocket()))
            {
                sf::Packet receivePacket;

                 if (Clients[i].getSocket()->receive(receivePacket) == sf::Socket::Done)
                {
                    UINT checkData;
                    receivePacket >> checkData;
                       
                    switch(checkData)
                    {
                    case DATA::XPOS:
                    {
                        float xPos;
                        receivePacket >> xPos;
                        Clients[i].setxPos(xPos);
                        std::cout << "xPos vaut : " << xPos << std::endl;
                        sf::Packet sendPacket;
                        sendPacket << INFO << "Le serveur a reçu votre position X ! ";
                        Clients[i].getSocket()->send(sendPacket);
                    }
                    break;
                    }
                }
            }
        }
    }

 

Et ça marche sans aucun problème si je renvoi l'information au client TOUT DE SUITE après grâce à mon packet sendPacket, le client reçoit bien la phrase "Le serveur a reçu votre position X ! ".

MAIS car oui il y a un MAIS, si je veux envoyer DIRECTEMENT une information à mon client sans que celui-ci m'est au préalablement envoyé un paquet comme par exemple :

sf::Packet sendPacket;
sendPacket << DATA::INFO << "Salut!";
Clients[i].getSocket()->send(sendPacket);
 

Mon client ne reçoit pas la phrase :-( il reçoit bien l'énumération qui indique qu'il s'agit de DATA::INFO mais la string sensée recevoir "Salut !" est vide....

Et pareil avec un booléen, un entier ou autre...
Pourquoi cette perte de données soudaine ?

Donc mes questions sont les suivantes :

-Comment je pourrais faire afin d'envoyer une information à un Client sans que celui-ci m'est envoyé d'abord un packet ?

-Pourquoi mon Client reçoit-il correctement l'énumération mais pas son contenu, alors que lorsque je procède à un renvoi direct après une réception, cela fonctionne ?


Merci infiniment car là, je suis complètement largué pour le coup.... ça me semble illogique comme problème...
« Modifié: Juin 29, 2017, 10:17:06 pm par Slash94 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re: Problème de réception de données côté Client..
« Réponse #1 le: Juin 30, 2017, 07:53:08 am »
Tu ne montres que le code qui fonctionne, ce serait bien de voir celui qui pose problème... ;) (comment se fait l'envoi spontané, décodage de l'autre côté, ...)
Laurent Gomila - SFML developer

Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #2 le: Juin 30, 2017, 11:24:12 am »
Salut Laurent, ça fait un petit baille :-)
Toujours fidèle au poste à ce que je vois !

[Petite apparté*] Alors JE SAIS PERTINEMMENT que la meilleure gestion qui soit c'est celle ou c'est LE SERVEUR qui détermine tout (positions en temps réel etc etc ) et non le Client, je le sais très bien mais ce n'est pas la question que je pose dans ce poste, donc ne nous attardons pas sur cette question de " faille " ou " d'optimisation idéale" mais plutôt sur comment résoudre mon problème qui a tendance à m'énerver copieusement ! :-)

Côté Client, on check si un paramètre change en le comparant à une structure déclarée dans ma classe Network, si c'est le cas, hop, on envoie la modification dont il est question au serveur :

void Network::sendData(float timeSend, MainPlayer &mainPlayer, Map& map)
{
    if (m_clockSend.getElapsedTime().asMilliseconds()>timeSend)
    {
        if (mainPlayerData.username != mainPlayer.getUsername())
        {
            mainPlayerData.username = mainPlayer.getUsername();
            sf::Packet sendPacket;
            sendPacket << DATA::USERNAME << mainPlayerData.username;
            m_socket.send(sendPacket);
        }

        if (mainPlayerData.mapname != mainPlayer.getMapName())
        {
            mainPlayerData.mapname = mainPlayer.getMapName();
            sf::Packet sendPacket;
            sendPacket << DATA::MAPNAME << mainPlayerData.mapname;
            m_socket.send(sendPacket);
        }

        if (mainPlayerData.position.x != mainPlayer.getPosition().x)
        {
            mainPlayerData.position.x = mainPlayer.getPosition().x;
            sf::Packet sendPacket;
            sendPacket << DATA::XPOS << mainPlayerData.position.x;
            m_socket.send(sendPacket);
        }

        if (mainPlayerData.position.y != mainPlayer.getPosition().y)
        {
            mainPlayerData.position.y = mainPlayer.getPosition().y;
            sf::Packet sendPacket;
            sendPacket << DATA::YPOS << mainPlayerData.position.y;
            m_socket.send(sendPacket);
        }

        if (mainPlayerData.anim.x != mainPlayer.getAnim().x)
        {
            mainPlayerData.anim.x = mainPlayer.getAnim().x;
            sf::Packet sendPacket;
            sendPacket << DATA::XANIM << mainPlayer.getAnim().x;
            m_socket.send(sendPacket);
        }

        if (mainPlayerData.anim.y != mainPlayer.getAnim().y)
        {
            mainPlayerData.anim.y = mainPlayer.getAnim().y;
            sf::Packet sendPacket;
            sendPacket << DATA::YANIM << mainPlayer.getAnim().y;
            m_socket.send(sendPacket);
        }

        if (mainPlayerData.life != mainPlayer.getLife())
        {
            mainPlayerData.life = mainPlayer.getLife();
            sf::Packet sendPacket;
            sendPacket << DATA::LIFE << mainPlayerData.life;
            m_socket.send(sendPacket);
        }

        m_clockSend.restart();
    }
}
 

Toujours côté Client, je reçois les informations provenant du serveur de la sorte :
( chaque donnée est identifiable grâce à son préfixe énuméré )

void Network::receiveData(std::vector<OnlinePlayer>&onlinePlayer)
{
    UINT checker;
    sf::Packet receivePacket;

    if (m_socket.receive(receivePacket) == sf::Socket::Done)
    {

    USHORT idNumber;
    receivePacket >> checker >> idNumber;
    std::cout << "checker = " << checker << std::endl;
    std::cout << "idNumber = " << idNumber << std::endl;

    if (!onlinePlayer[idNumber].getState())
        onlinePlayer[idNumber].setState(true);

    switch(checker)
    {
    case DATA::USERNAME:
        {
        std::string username;
        receivePacket >> username;
        onlinePlayer[idNumber].setUsername(username);
        }
        break;
    case DATA::MAPNAME:
        {
        std::string mapname;
        receivePacket >> mapname;
        onlinePlayer[idNumber].setMapname(mapname);
        }
    break;
    case DATA::XPOS:
        {
        float xPos;
        receivePacket >> xPos;
        onlinePlayer[idNumber].setxPos(xPos);
        }
        break;
    case DATA::YPOS:
        {
        float yPos;
        receivePacket >> yPos;
        onlinePlayer[idNumber].setyPos(yPos);
        }
        break;
    case DATA::XANIM:
        {
            int xAnim;
            receivePacket >> xAnim;
            onlinePlayer[idNumber].setxAnim(xAnim);
        }
        break;
    case DATA::YANIM:
        {
            int yAnim;
            receivePacket >> yAnim;
            onlinePlayer[idNumber].setyAnim(yAnim);
        }
        break;
    case DATA::STATE:
        {
        bool state;
        receivePacket >> state;
        onlinePlayer[idNumber].setState(state);
        if (!onlinePlayer[idNumber].getState())
            onlinePlayer[idNumber].init();
        }
        break;
    case DATA::INFO:
        {
            std::string info;
            receivePacket >> info;
            std::cout << "Info : " << info << std::endl;
            if (info == "FULL")
            {
                std::cout << "Serveur plein.." << std::endl;
                exit(0);
            }
        }
        break;
    case DATA::WEATHER:
        {
            bool weather;
            receivePacket >> weather;
            std::cout << "weather : " << weather << std::endl;
            mapData.weather = weather;
            std::cout << "mapData.weather : " << mapData.weather << std::endl;
        }
        break;

    }

    }
}
 

Et enfin, côté serveur, je traite la réception et le renvoi de données de cette manière là :

void Network::receiveAndSendData()
{
    for (UINT i = 0 ; i < m_Clients.size() ; i++)
    {
        if (m_Clients[i].getIdNumber() != 0)
        {

            if (m_socketSelector.isReady(*m_Clients[i].getSocket()))
            {
                sf::Packet receivePacket;

                if (m_Clients[i].getSocket()->receive(receivePacket) == sf::Socket::Done)
                {

                ///Le checker permettra de vérifier l'énumération reçue
                UINT checker;
                receivePacket >> checker;

                switch(checker)
                {
                    case DATA::USERNAME:
                    {
                        std::string username;
                        receivePacket >> username;
                        std::cout << "username recu du client " << m_Clients[i].getIdNumber() << " : " << username << std::endl;
                        m_Clients[i].setUsername(username);

                        sf::Packet sendPacket;
                        sendPacket << DATA::USERNAME << m_Clients[i].getIdNumber()
                                   << m_Clients[i].getUsername();
                        for (UINT s = 0 ; s < m_Clients.size() ; s++)
                        {
                            if (i!=s && m_Clients[s].getIdNumber() != 0)
                                m_Clients[s].getSocket()->send(sendPacket);
                        }
                    }
                    break;
                    case DATA::MAPNAME:
                    {
                        std::string mapname;
                        receivePacket >> mapname;
                        std::cout << "mapname recu du client " << m_Clients[i].getIdNumber() << " : " << mapname << std::endl;
                        m_Clients[i].setMapname(mapname);

                        sf::Packet sendPacket;
                        sendPacket << DATA::MAPNAME << m_Clients[i].getIdNumber()
                                   << m_Clients[i].getMapname();
                        for (UINT s = 0 ; s < m_Clients.size() ; s++)
                        {
                            if (i!=s && m_Clients[s].getIdNumber() != 0)
                                m_Clients[s].getSocket()->send(sendPacket);
                        }
                    }
                    break;
                    case DATA::STATE:
                    {
                        bool state;
                        receivePacket >> state;
                        m_Clients[i].setState(state);

                        sf::Packet sendPacket;
                        sendPacket << DATA::STATE << m_Clients[i].getIdNumber() << m_Clients[i].getState();

                        for (UINT s = 0 ; s < m_Clients.size() ; s++)
                        {
                            if (i!=s && m_Clients[s].getIdNumber() !=0)
                                m_Clients[s].getSocket()->send(sendPacket);
                        }

                        if (!m_Clients[i].getState())
                        {
                            std::cout << m_Clients[i].getUsername() << " s'est deconnecte." << std::endl;
                            m_socketSelector.remove(*m_Clients[i].getSocket());
                            m_Clients[i].init();
                        }
                    }
                    break;
                    case DATA::XPOS:
                    {
                        float xPos;
                        receivePacket >> xPos;
                        std::cout << "xPos recu du client " << m_Clients[i].getIdNumber() << " : " << xPos << std::endl;
                        m_Clients[i].setxPos(xPos);

                        sf::Packet sendPacket;
                        sendPacket << DATA::XPOS << m_Clients[i].getIdNumber()
                                   << m_Clients[i].getPosition().x;

                        for (UINT s = 0 ; s < m_Clients.size() ; s++)
                        {
                            if (i!=s && m_Clients[s].getIdNumber() != 0)
                                m_Clients[s].getSocket()->send(sendPacket);

                        }

                    }
                    break;
                    case DATA::YPOS:
                    {
                        float yPos;
                        receivePacket >> yPos;
                        std::cout << "yPos recu du client " << m_Clients[i].getIdNumber() << " : " << yPos << std::endl;
                        m_Clients[i].setyPos(yPos);

                        sf::Packet sendPacket;
                        sendPacket << DATA::YPOS << m_Clients[i].getIdNumber()
                                   << m_Clients[i].getPosition().y;
                        for (UINT s = 0 ; s < m_Clients.size() ; s++)
                        {
                            if (i!=s && m_Clients[s].getIdNumber() != 0)
                                m_Clients[s].getSocket()->send(sendPacket);
                        }
                    }
                    break;
                    case DATA::XANIM:
                    {
                        int xAnim;
                        receivePacket >> xAnim;
                        std::cout << "xAnim recu du client " << m_Clients[i].getIdNumber() << " : " << xAnim << std::endl;
                        m_Clients[i].setxAnim(xAnim);

                        sf::Packet sendPacket;
                        sendPacket << DATA::XANIM << m_Clients[i].getIdNumber()
                                   << m_Clients[i].getAnim().x;
                        for (UINT s = 0 ; s < m_Clients.size() ; s++)
                        {
                            if (i!=s && m_Clients[s].getIdNumber() != 0)
                                m_Clients[s].getSocket()->send(sendPacket);
                        }
                    }
                    break;
                    case DATA::YANIM:
                    {
                        int yAnim;
                        receivePacket >> yAnim;
                        std::cout << "yAnim recu du client " << m_Clients[i].getIdNumber() << " : " << yAnim << std::endl;
                        m_Clients[i].setyAnim(yAnim);

                        sf::Packet sendPacket;
                        sendPacket << DATA::YANIM << m_Clients[i].getIdNumber()
                                   << m_Clients[i].getAnim().y;
                        for (UINT s = 0 ; s < m_Clients.size() ; s++)
                        {
                            if (i!=s && m_Clients[s].getIdNumber() != 0)
                                m_Clients[s].getSocket()->send(sendPacket);
                        }
                    }
                    break;
                    case DATA::ATTACK:
                    {
                        bool attack;
                        receivePacket >> attack;
                        for (UINT a = 0 ; a < m_Clients.size() ; a++)
                        {
                            if (i!=a && m_Clients[a].getIdNumber() != 0)
                            {
                                if (m_Clients[i].checkPerimeter(m_Clients[a]))
                                {
                                    m_Clients[i].attack(m_Clients[a]);
                                    sf::Packet sendPacket;
                                    sendPacket << DATA::DAMAGE << m_Clients[i].getIdNumber()
                                               << m_Clients[a].getLife();
                                    m_Clients[a].getSocket()->send(sendPacket);

                                    for (UINT s = 0 ; s < m_Clients.size() ; s++)
                                    {
                                        if (a!=s && m_Clients[s].getIdNumber() != 0)
                                        {
                                            sf::Packet sendPacket;
                                            sendPacket << DATA::LIFE << m_Clients[a].getIdNumber()
                                                       << m_Clients[a].getLife();
                                            m_Clients[s].getSocket()->send(sendPacket);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    break;
                    }
                }
            }

        }
    }
}
 

Tout ça fonctionne parfaitement bien MAIS lorsque je désire envoyer une information DIRECTEMENT aux clients depuis le serveur, le client ne reçoit que le type énuméré et non le reste...

Exemple de code qui foire :

    for (UINT i = 0 ; i < m_Clients.size() ; i++)
    {
        if (m_Clients[i].getIdNumber() != 0)
        {
            if (m_socketSelector.isReady(*m_Clients[i].getSocket()))
            {
                        sf::Packet sendPacket;
                        sendPacket << DATA::INFO << 0 << "Le serveur vous parle !";
                        m_Clients[i].getSocket()->send(sendPacket);
             }
        }
    }
 

Le client reçoit bien le DATA::INFO ( car il sait qu'il s'agit d'une INFO ) mais ensuite, lorsqu'il s'agit d'extraire la string "Le serveur vous parle !", impossible, la string est vide, comme si il y avait eu une perte.. :-(
« Modifié: Juin 30, 2017, 11:43:00 am par Slash94 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re: Problème de réception de données côté Client..
« Réponse #3 le: Juin 30, 2017, 11:51:53 am »
A mon avis tu as un problème de type. Tu mets "0" dans le paquet, qui est de type int et côté serveur tu tentes d'extraire un USHORT, qui est plus que probablement moitié moins gros.

Déjà, utilise les types à taille fixe standards (uint16_t, etc.). USHORT on ne sait pas d'où ça vient et on ne sait pas quelle taille ça fait.

Ensuite assure-toi de toujours explicitement envoyer les mêmes types que tu vas décoder de l'autre côté. Les variables litérales du genre 0 c'est mauvais, on préfèrera uint16_t(0) par exemple.

Au pire, si tu veux faire vraiment propre, utilise des structures propres à chaque message, partagées entre serveur et client :

struct InfoMessage
{
    uint16_t id;
    std::string message;
};

// operator <<(sf::Packet) et operator >>(sf::Packet) ...

// envoi :
packet << DATA::INFO << InfoMessage{0, "blop"};

// réception :
InfoMessage info;
packet >> info;
std::cout << "id: " << info.id << ", message: " << info.message << std::endl;

C'est plus verbeux côté implémentation, mais c'est ensuite plus carré et safe côté utilisation.
Laurent Gomila - SFML developer

Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #4 le: Juin 30, 2017, 05:26:22 pm »
Merci pour ta réactivité Laurent !
J'essayerais d'ores et déjà de procéder selon ta méthode quand je rentrerais chez moi, néanmoins je tiens a insister sur le fait que lorsque le client a au préalablement adressé un packet au serveur, admettons DATA::XPOS et qu ensuite je renvoi tout de suite au client par un DATA:INFO << 0 << "Le serveur a bien reçu votre position X !";
La le client recevra bien le packet dans son intégralité alors que si j'envoi directement ce packet , le client ne recevra pas tout ... Bizarre, non ?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re: Problème de réception de données côté Client..
« Réponse #5 le: Juin 30, 2017, 05:51:32 pm »
Dans les autres exemples d'envoi d'info que tu as postés, je ne vois pas le paramètre "0", immédiatement après INFO on a directement la chaîne.

D'ailleurs ça vaut aussi pour les autres messages : parfois il y a l'ID, parfois pas. C'est un peu confus tout ça.
« Modifié: Juin 30, 2017, 05:54:09 pm par Laurent »
Laurent Gomila - SFML developer

Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #6 le: Juin 30, 2017, 08:04:33 pm »
Ben non Laurent, j'avais bel et bien écrit

            if (m_socketSelector.isReady(*m_Clients[i].getSocket()))
            {
                        sf::Packet sendPacket;
                        sendPacket << DATA::INFO << 0 << "Le serveur vous parle !";
                        m_Clients[i].getSocket()->send(sendPacket);
             }
 


:-)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re: Problème de réception de données côté Client..
« Réponse #7 le: Juin 30, 2017, 08:32:13 pm »
Moi je vois ça par exemple :

Citer
sendPacket << INFO << "Le serveur a reçu votre position X ! ";
sendPacket << DATA::USERNAME << mainPlayerData.username;
sendPacket << DATA::INFO << "Salut!";
...
Laurent Gomila - SFML developer

Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #8 le: Juillet 01, 2017, 02:51:41 pm »
Salut Laurent :-)

Oui, c'est normal, c'est comme cela que je procède côté client, en effet.

Le serveur lui, sait de quel client ça vient grâce à sa socket, il retrouve son ID automatiquement et peut renseigner les autres joueurs sur le changement de coordonnées qu'un joueur a fait et renvoyant l'information aux autres joueurs, cette fois-ci avec l'ID du joueur concerné, et côté client, on RÉCEPTIONNE avec l'ID du joueur dont il est question, ça fonctionne très bien comme ça..

En fait, mon problème c'est que je n'arrive pas à envoyer une information directement depuis mon Serveur, on dirait qu'il est " bloqué ".

J'ai refait entièrement un petit programme Serveur/Client de test qui fonctionne mais avec le même problème :

Côté Serveur


#include "../../Headers/Network/Network.h"

Network::Network(std::vector<Client>& vecClient) :
    m_Client(vecClient)
{

}

void Network::Launch(USHORT port)
{
    m_port = port;

    if (m_listener.listen(m_port) == sf::Socket::Done)
    {
        std::cout << "Serveur lance sur le port " << m_port << std::endl;
        m_listener.setBlocking(false);
        m_socketSelector.add(m_listener);
        m_isRunning = true;
    } else {
        std::cout << "Impossible de lancer le serveur sur le port " << m_port << std::endl;
    }

}

void Network::MainLoop()
{
    if (m_socketSelector.wait())
    {
        if (m_socketSelector.isReady(m_listener))
        {
            PushNewUser();
        } else {
            SendToClients();
            ReceiveAndSendData();
        }
    }

}

void Network::PushNewUser()
{
        sf::TcpSocket *socket = new sf::TcpSocket();
        socket->setBlocking(false);
        m_listener.accept(*socket);

        std::cout << "Une connexion est detectee." << std::endl;

        sf::Uint16 idNumber = 1;

        while (m_Client[idNumber].getIdNumber()!=0)
            idNumber++;

            if (idNumber <= 4)
            {
                m_Client[idNumber].setSocket(socket);
                m_Client[idNumber].setState(true);
                m_Client[idNumber].setIdNumber(idNumber);
                m_socketSelector.add(*m_Client[idNumber].getSocket());
            } else {
            m_blackList.push_back(socket);
            CheckBlackList();
        }
}

void Network::CheckBlackList()
{
    if (m_blackList.size() > 0)
    {
        for (unsigned int i = 0 ; i < m_blackList.size() ; i++)
        {
            sf::Packet sendPacket;
            sendPacket << DATA::INFO << "FULL";
            m_Client[i].getSocket()->send(sendPacket);
            m_blackList.erase(m_blackList.begin()+i);
        }
    }
}

void Network::SendToClients()
{
    if (_kbhit())
    {
        if (_getch() == 'w')
        {
            sf::Packet packTest;
            packTest << DATA::INFO << sf::Uint16(0) << "Salut ! ";
            for (unsigned int i = 0 ; i < m_Client.size() ; i++)
            {
                if (m_Client[i].getIdNumber() !=0)
                {
                    sf::Packet packTest;
                    packTest << DATA::INFO << sf::Uint16(0) << "Salut ! ";
                    m_Client[i].getSocket()->send(packTest);
                    std::cout << "Message du serveur envoye au(x) client(s)." << std::endl;
                }
            }
        }
    }
}

void Network::ReceiveAndSendData()
{
    for (unsigned int i = 0 ; i < m_Client.size() ; i++)
    {
        if (m_Client[i].getIdNumber()!=0 && m_socketSelector.isReady(*m_Client[i].getSocket()))
        {
            sf::Packet receivePacket;
            if (m_Client[i].getSocket()->receive(receivePacket) == sf::Socket::Done)
            {
                sf::Uint32 Checker;
                receivePacket >> Checker;

                switch(Checker)
                {
                    case DATA::INFO:
                    {
                        std::string information;
                        receivePacket >> information;
                        std::cout << "DATA::INFO du Client N " << m_Client[i].getIdNumber() << " : " << information << std::endl;
                        sf::Packet sendPacket;
                        sendPacket << DATA::INFO << information;
                        m_Client[i].getSocket()->send(sendPacket);
                    }
                    break;

                    case DATA::USERNAME:
                    {
                        std::string username;
                        receivePacket >> username;
                        m_Client[i].setUsername(username);
                        std::cout << username << " vient de se connecter." << std::endl;
                        sf::Packet sendPacket;
                        sendPacket << DATA::USERNAME << sf::Uint16(0) << m_Client[i].getUsername();
                        m_Client[i].getSocket()->send(sendPacket);
                    }
                    break;

                    case DATA::DIRECTION:
                    {
                        sf::Uint32 direction;
                        receivePacket >> direction;
                        std::cout << "DATA::DIRECTION du Client N " << m_Client[i].getIdNumber() << " : " << direction << std::endl;
                        sf::Packet sendPacket;
                        sendPacket << DATA::DIRECTION << sf::Uint16(0) << direction;
                        m_Client[i].getSocket()->send(sendPacket);
                    }
                    break;
                }
            }
        }
    }
}

///GETTERS///
bool Network::isRunning() const { return m_isRunning; }
 

Côté Client


#include "../../Headers/Network/Network.h"

Network::Network(Client& client) :
    m_Client(client)
{

}

void Network::ConnectToServer(std::string ipAddress, USHORT Port)
{
    if (m_socket.connect(ipAddress, Port) == sf::Socket::Done)
    {
        std::cout << "Connexion reussie au serveur." << std::endl;
        m_isRunning = true;
        m_socket.setBlocking(false);
    } else {
        std::cout << "Connexion impossible..." << std::endl;
        exit(0);
    }
}

void Network::SendData(float timeSend)
{
    if (m_clockSend.getElapsedTime().asMilliseconds() > timeSend)
    {
        if (m_Client.getDirection() != m_structData.Direction)
        {
            m_structData.Direction = m_Client.getDirection();
            if (m_structData.Direction !=0)
            {
                sf::Packet sendPacket;
                sendPacket << DATA::DIRECTION << m_structData.Direction;
                m_socket.send(sendPacket);
                std::cout <<"Direction envoyee au serveur" << std::endl;
                m_structData.Direction = 0;
            }
        }

        if (m_Client.getUsername() != m_structData.Username)
        {
            m_structData.Username = m_Client.getUsername();
            sf::Packet sendPacket;
            sendPacket << DATA::USERNAME << m_structData.Username;
            m_socket.send(sendPacket);
            std::cout <<"Username envoye au serveur" << std::endl;
        }

        m_clockSend.restart();
    }

}

void Network::ReceiveData()
{
    sf::Packet receivePacket;
    if (m_socket.receive(receivePacket) == sf::Socket::Done)
    {
        sf::Uint32 Checker;
        sf::Uint16 idNumber;

        receivePacket >> Checker >> idNumber;

        switch(Checker)
        {
        case DATA::INFO:
            {
                std::string info;
                receivePacket >> info;
                std::cout << "Recu info : " << info << std::endl;
            }
            case DATA::DIRECTION:
            {
                sf::Uint32 direction;
                receivePacket >> direction;
                std::cout << "Le serveur vous renvoi votre direction : " << direction << std::endl;
            }
            break;
        }
    }
}

///GETTERS///
bool Network::isRunning() const { return m_isRunning; }
 

J'ai fait, pour le test, en sorte que si l'on appuie sur la touche W, que ça envoi l'information aux Clients avec une itération, mais l'information n'arrive pas instantanément, il faut obligatoirement que les Clients concernés aient renvoyé un message pour que le serveur envoi le sien, comme si il était bloqué / en attente..

Exemple :


Mon serveur à gauche, mon client à droite.

Lorsque j'appuie sur la touche W sur mon serveur, il ne se passe rien côté serveur, ni client..

PAR CONTRE si le client change sa position ALORS le serveur envoi finalement l'information, mais j'ai aussi un bug car le Client reçoit une DATA::DIRECTION de 2292880 alors que je n'ai jamais demandé au serveur de renvoyer la direction à ce moment-là ( et surtout pas avec cette donnée faussée ).

Ma question ultime est, comment faire pour que lorsque je presse la touche 'W' sur mon serveur, celui-ci envoi instantanément aux clients la DATA::INFO que j'ai envie d'envoyer ?
D'où viendrait aussi le bug inhérent à la direction ?

PS : Voici mon enumération de mon Network.h qui est la même de chaque côté :

    enum DATA:sf::Uint32{INFO, USERNAME, DIRECTION};
 

Merci infiniment ! :-)


Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #9 le: Juillet 01, 2017, 02:54:09 pm »
PS : Pour voir le screen entièrement, faire "clique droit > ouvrir dans un nouvel onglet " car il ne s'affiche pas entièrement :-/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re: Problème de réception de données côté Client..
« Réponse #10 le: Juillet 01, 2017, 07:42:44 pm »
Il manque le "break" après "case DATA::INFO:" côté client. Sinon, pourquoi est-ce que, côté serveur, tu utilises à la fois des sockets non-bloquantes et un sélecteur ?

Ceci-dit ça n'explique sans doute toujours pas ton problème, mais ton code est encore trop compliqué pour facilement déceler une éventuelle erreur de logique. Tu devrais grandement simplifier : pas de classe avec plein de fonctions, pas de gestion de pleins de clients, etc. ; puisque le problème est l'envoi spontané d'un serveur vers un client, écris un code qui ne fait que ça, et rien d'autre.
« Modifié: Juillet 01, 2017, 07:45:23 pm par Laurent »
Laurent Gomila - SFML developer

Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #11 le: Juillet 01, 2017, 08:02:49 pm »
Ah oui, merde pour le break ! L'erreur pour DIRECTION doit venir de la !
Ben il me semblait qu'il etait primordial d'employer socetselector quand on faisait du multi clients pour éviter de faire appel à des threads .
En fait j'aimerais que mon serveur puisse gérer les échanges entre les clients ET qu'il soit possible de contacter les clients directement par le biais du serveur ..
Comment T'y prendrais-tu ?
Merci :-))

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re: Problème de réception de données côté Client..
« Réponse #12 le: Juillet 02, 2017, 09:09:49 am »
Si tes sockets sont non-bloquantes alors tu n'as besoin de rien d'autre. Si tu utilises un sélecteur, il faut garder les sockets bloquantes, et tu peux toutes les gérer dans un seul thread. Sinon il faut un thread par client.
Laurent Gomila - SFML developer

Slash94

  • Jr. Member
  • **
  • Messages: 89
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #13 le: Juillet 02, 2017, 01:53:53 pm »
Merci infiniment Laurent, j'ai résolu le problème en supprimant le Selector ! Je viens d'apprendre quelque chose finalement :-]

Voici mon Serveur complet & parfaitement OK maintenant :

#include "../../Headers/Network/Network.h"

Network::Network(std::vector<Client>& vecClient) :
    m_Client(vecClient)
{

}

void Network::Launch(USHORT port)
{
    m_port = port;

    if (m_listener.listen(m_port) == sf::Socket::Done)
    {
        std::cout << "Serveur lance sur le port " << m_port << std::endl;
        m_isRunning = true;
        m_listener.setBlocking(false);
    } else {
        std::cout << "Impossible de lancer le serveur sur le port " << m_port << std::endl;
    }
}

void Network::MainLoop()
{
    PushNewUser();
    SendToClients();
    ReceiveAndSendData();
}

void Network::PushNewUser()
{
    sf::TcpSocket *socket = new sf::TcpSocket();
    socket->setBlocking(false);
    sf::Uint16 idNumber = 1;

    if (m_listener.accept(*socket) == sf::Socket::Done)
    {
        while (m_Client[idNumber].getIdNumber()!=0)
            idNumber++;

            if (idNumber <= 4)
            {
                m_Client[idNumber].setSocket(socket);
                m_Client[idNumber].setState(true);
                m_Client[idNumber].setIdNumber(idNumber);
            } else {
            m_blackList.push_back(socket);
            CheckBlackList();
        }
    }
}

void Network::CheckBlackList()
{
    if (m_blackList.size() > 0)
    {
        for (unsigned int i = 0 ; i < m_blackList.size() ; i++)
        {
            sf::Packet sendPacket;
            sendPacket << DATA::INFO << "FULL";
            m_Client[i].getSocket()->send(sendPacket);
            m_blackList.erase(m_blackList.begin()+i);
        }
    }
}

void Network::SendToClients()
{
    if (_kbhit())
    {
        if (_getch() == 'w')
        {
            for (unsigned int i = 0 ; i < m_Client.size() ; i++)
            {
                if (m_Client[i].getIdNumber() !=0)
                {
                    sf::Packet packTest;
                    packTest << DATA::INFO << sf::Uint16(0) << "Salut ! ";
                    m_Client[i].getSocket()->send(packTest);
                    std::cout << "Message du serveur envoye au(x) client(s)." << std::endl;
                }
            }
        }
    }
}

void Network::ReceiveAndSendData()
{
    for (unsigned int i = 0 ; i < m_Client.size() ; i++)
    {
        if (m_Client[i].getIdNumber()!=0)
        {
            sf::Packet receivePacket;
            if (m_Client[i].getSocket()->receive(receivePacket) == sf::Socket::Done)
            {
                sf::Uint32 checker;
                receivePacket >> checker;

                switch(checker)
                {
                    case DATA::INFO:
                    {
                        std::string information;
                        receivePacket >> information;
                        std::cout << "DATA::INFO du Client N " << m_Client[i].getIdNumber() << " : " << information << std::endl;
                        sf::Packet sendPacket;
                        sendPacket << DATA::INFO << information;
                        m_Client[i].getSocket()->send(sendPacket);
                    }
                    break;

                    case DATA::USERNAME:
                    {
                        std::string username;
                        receivePacket >> username;
                        m_Client[i].setUsername(username);
                        std::cout << username << " vient de se connecter." << std::endl;
                        sf::Packet sendPacket;
                        sendPacket << DATA::USERNAME << sf::Uint16(0) << m_Client[i].getUsername();
                        m_Client[i].getSocket()->send(sendPacket);
                    }
                    break;

                    case DATA::DIRECTION:
                    {
                        sf::Uint32 direction;
                        receivePacket >> direction;
                        std::cout << "DATA::DIRECTION du Client N " << m_Client[i].getIdNumber() << " : " << direction << std::endl;
                        sf::Packet sendPacket;
                        sendPacket << DATA::DIRECTION << sf::Uint16(0) << direction;
                        m_Client[i].getSocket()->send(sendPacket);
                    }
                    break;
                }
            }
        }
    }
}

///GETTERS///
bool Network::isRunning() const { return m_isRunning; }
 

Merci à toi ! UNE FOIS DE PLUS ! :-D
« Modifié: Juillet 02, 2017, 02:37:14 pm par Slash94 »

janf

  • Newbie
  • *
  • Messages: 45
    • Voir le profil
Re: Problème de réception de données côté Client..
« Réponse #14 le: Juillet 29, 2017, 07:20:17 pm »
Du coup j'ai pas compris comment le problème a été résolu, et en quoi c'est du à un Selector (ça fait beaucoup de code à lire ;) ).

A la base je t'aurais dis de faire attention dans ton instruction chaînée d'être bien sûr que l'opérateur ' << ' retourne bien une référence vers ton sf::Packet quand tu l'utilises avec des types personnalisés.

Pour ta question plus générale d'échange de paquets, il n'y a aucun obstacle à ce que le serveur contacte un client sans avoir au préalable reçu un message de celui-ci. Il suffit que ton serveur connaisse la liste des clients (connectés ou non (UDP)), et qu'il leur envoi un paquet quand tu le veux.

Il y a beaucoup de façons de procéder. Tu peux envoyer ton paquet immédiatement quand le serveur décide qu'il doit envoyer quelque chose à tel client. Tu peux aussi créer une file de paquets sortants, qui sera traitée, soit en la vidant complètement lors d'un tour de boucle de ton programme, soit en envoyant le paquet du bout de la file à chaque tour (permet d'équilibrer les opérations, premier arrivé premier servi, mais la boucle doit tourner vite et sans interruption).
Soit encore en ayant un thread qui s'occupe d'envoyer les paquets à destination lorsque la file n'est pas vide, mais là c'est plus compliqué et probablement pas le plus performant.

C'est juste que selon la complexité de ton programme tu peux en arriver à désirer un gestion "centralisée" de l'échange de messages, plutôt que d'avoir des fonctions send() un peu partout dans le code. Par exemple créer une class Transaction qui contient le paquet à envoyer et l'adresse du destinataire (ou le pointeur vers le socket), mais qui reste en vie après l'envoi, et ne disparaît que lorsqu'elle a reçu la réponse attendue, et qu'elle la transmise où il faut. Elle ne doit évidemment pas être bloquante. Les Transactions sont dans un conteneur, vérifiées à chaque tour du programme, et en sont effacées lorsque leur job est fini.

Ce sont juste des idées générales. Et probablement pas les meilleures.