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

Auteur Sujet: [Résolu][TCP/Packets] Problème de transmission de données.  (Lu 4339 fois)

0 Membres et 1 Invité sur ce sujet

CookieSpirit

  • Newbie
  • *
  • Messages: 4
    • Voir le profil
Bonjour, je code actuellement un petit jeu en utilisant la SFML.
Ayant fait divers entraînements par le passé pour maîtriser au mieux cette librairie, j'ai décidé cette fois de me lancer dans la programmation Réseau.

Edit important : j'utilise SFML 2.0 avec code::blocks sur Windows 7, j'avais ommis de le préciser.

Le choix du TCP m'a semblé le plus simple à mettre en place pour apprendre le fonctionnement réseau (il n'est pas forcément le plus adapté à mon projet, mais ce n'est qu'un entraînement).

Mon problème : Le serveur et le client sont deux applications différentes. Lorsque le client tente de se connecter au serveur, tout fonctionne parfaitement (le serveur affiche le message de connexion, renvoie 1 au client pour lui indiquer qu'il est prêt à communiquer). Une fois la connexion établie, l'actualisation des positions est totalement hasardeuse. C'est à dire que j'obtient des positions qui ne rentrent même pas dans un int... le jeu saccade et la position est rafraîchie toutes les 10sec (et est en plus fausse).

Tests effectués : Changer de port, mettre 1 packet pour la reception et 1 pour l'envoi, tester en ligne (via hamachi, avec la bonne ip bien entendu, l'autre client se connecte également parfaitement mais l'erreur est exactement la même qu'en local.)

Le code coté serveur :

Serveur.hpp:

#include <SFML/Network.hpp>
#include <iostream>
#include <sstream>

class Serveur
{
    public:
    Serveur();
    void initServeur();
    void attenteConnexions();
    void recevoirDonnees();
    void envoyerDonnees();
    ~Serveur();
    private:
    int nbJoueurs;
    int nbJoueursMax;
    int port;
    int test;
    bool client1Connecte;
    bool client2Connecte;
    int delay1;
    int delay2;
    sf::TcpListener listener;
    sf::TcpSocket socket;
    sf::TcpSocket client1;
    sf::TcpSocket client2;
    sf::TcpSocket clientMax;
    sf::Packet packet1;
    sf::Packet packet1bis;
    sf::Packet packet2;
    sf::Packet packet2bis;
    sf::Packet packetMax;
    // Infos joueur 1
    int posX1;
    int posY1;
    //Infos joueur 2
    int posX2;
    int posY2;
};

Serveur.cpp:

#include "serveur.hpp"

Serveur::Serveur(): nbJoueurs(0), nbJoueursMax(2), port(15230), test(0), client1Connecte(false), client2Connecte(false), delay1(0), delay2(0)
{

}

void Serveur::initServeur()
{
    std::cout << "[Serveur] Initialisation du serveur sur le port " << port << " ..." << std::endl;
    socket.setBlocking(false);
    listener.setBlocking(false);
    client1.setBlocking(false);
    client2.setBlocking(false);
    if(listener.listen(port) != sf::Socket::Done)
    {
        std::cout << "[Erreur] Erreur lors de l'initialisation du Listener sur le port " << port << std::endl;
        std::cout << "[Aide] Le port est probablement ferme ou deja utilise" << std::endl;
    }
    else
    {
        std::cout << "[Serveur] serveur ON ! Port utilise : " << port << std::endl;
        std::cout << "[Serveur] en attente de connexions..." << std::endl;
    }
}

void Serveur::attenteConnexions()
{
    if(!client1Connecte)
    {
        if(listener.accept(client1)==sf::Socket::Done)
        {
            packet1 << 1;
            client1.send(packet1);
            std::cout << "Client 1 s'est connecte" << std::endl;
            nbJoueurs++;
            client1Connecte = true;
            std::cout << "Nombres de joueurs : " << nbJoueurs << "/" << nbJoueursMax << std::endl;
        }
    }
    if(!client2Connecte)
    {
        if(listener.accept(client2)==sf::Socket::Done)
        {
            packet2 << 1;
            client2.send(packet2);
            std::cout << "Client 2 s'est connecte" << std::endl;
            nbJoueurs++;
            client2Connecte = true;
            std::cout << "Nombres de joueurs : " << nbJoueurs << "/" << nbJoueursMax << std::endl;
        }
    }
    if(nbJoueurs == nbJoueursMax)
    {
        if(listener.accept(clientMax)==sf::Socket::Done && client1Connecte && client2Connecte)
        {
            std::cout << "Un jouer tente de se connecter alors que le max est atteint" << std::endl;
            packetMax << -1;
            clientMax.send(packetMax);
        }
    }
}

void Serveur::recevoirDonnees()
{
    if(client1Connecte)
    {
        if(client1.receive(packet1) == sf::Socket::Done)
        {
            packet1 >> posX1 >> posY1;
            delay1 = 0;
        }
        else
        {
            delay1++;
        }
        if(delay1 > 1000000)
        {
            std::cout << "Client 1 est deconnecte" << std::endl;
            nbJoueurs--;
            client1Connecte = false;
            delay1 = 0;
        }
    }
    if(client2Connecte)
    {
         if(client2.receive(packet2) == sf::Socket::Done)
        {
            packet2 >> posX2 >> posY2;
            delay2 = 0;
        }
        else
        {
            delay2++;
        }
        if(delay2 > 1000000)
        {
            std::cout << "Client 2 est deconnecte" << std::endl;
            nbJoueurs--;
            client2Connecte = false;
            delay2 = 0;
        }
    }
}

void Serveur::envoyerDonnees()
{
    if(client1Connecte)
    {
        if(client2Connecte)
        {
            packet1 << posX2 << posY2;
            client1.send(packet1);
        }
    }
    if(client2Connecte)
    {
        if(client1Connecte)
        {
            packet2 << posX1 << posY1;
            client2.send(packet2);
        }
    }
}

Serveur::~Serveur()
{

}
 


Le code coté client (je ne vous mets pas la gestion des évenements etc, juste l'unique partie qui touche au réseau

reseau.hpp:

#include <SFML/Graphics.hpp>
#include <SFML/Network.hpp>
#include <iostream>
#include <sstream>

class Reseau
{
    public:
    Reseau();
    void initClient();
    void chargerRessources();
    void connexionServeur();
    void envoyerInfos(int persoX, int persoY);
    void recevoirInfos();
    void afficherAutres(sf::RenderWindow &app);
    ~Reseau();
    private:
    //Partie Réseau
    int test;
    int port;
    int canSend;
    sf::TcpSocket socket;
    sf::Packet packet;
    sf::IpAddress adresse;
    //Infos Joueur 2
    int posX2;
    int posY2;
    //Partie Graphique
    sf::Texture persoTile;
    sf::Sprite basPause;
};

reseau.cpp:

#include "reseau.hpp"

Reseau::Reseau() : port(15230), canSend(0)
{

}

void Reseau::initClient()
{
    test = 50;
    port = 15230;
    socket.setBlocking(false);
}

void Reseau::chargerRessources()
{
    persoTile.loadFromFile("resources/personnages/0.png");
    basPause.setTexture(persoTile);
    basPause.setTextureRect(sf::IntRect(0, 0, 32, 48));
}

void Reseau::connexionServeur()
{
    if(canSend == 0)
    {
        socket.connect("127.0.0.1",port);
        if(socket.receive(packet) == sf::Socket::Done)
        {
            packet >> canSend;
        }
        if(canSend == -1)
        {

        }
        if(canSend == 1)
        {

        }
    }
}

void Reseau::envoyerInfos(int persoX, int persoY)
{
    if(canSend == 1)
    {
        packet << persoX << persoY;
        socket.send(packet);
    }
}

void Reseau::recevoirInfos()
{
    if(canSend == 1)
    {
        if(socket.receive(packet) == sf::Socket::Done)
        {
            packet >> posX2 >> posY2;
            std::cout << posX2 << " : " << posY2 << std::endl;
            basPause.setPosition(posX2, posY2-16);
        }
    }
}

void Reseau::afficherAutres(sf::RenderWindow &app)
{
    if(canSend == 1)
    {
        app.draw(basPause);
    }
}

Reseau::~Reseau()
{

}
 

Dans le main, toutes les fonctions sont executées, dans cet ordre pour le client :

        map.test(app);
        perso.afficherPerso(app);
        perso.afficherCheveux(app);
        perso.centrerVue(app,vue);
        reseau.connexionServeur();
        reseau.envoyerInfos(perso.getPosX(), perso.getPosY());
        reseau.recevoirInfos();
        reseau.afficherAutres(app);
        if(isFocused)
        {
            perso.bougerPerso();
        }

les fonctions getPos, on ne peut plus simples:
int Perso::getPosX()
{
    return posX;
}

int Perso::getPosY()
{
    return posY;
}

et pour le serveur :

int main()
{
    int continuer = true;
    Serveur serveur;
    serveur.initServeur();
    while(continuer)
    {
        serveur.attenteConnexions();
        serveur.recevoirDonnees();
        serveur.envoyerDonnees();
    }
}


Si vous avez besoin d'autres informations, je répondrai au plus vite possible.
En espérant que vous m'aiderez à trouver mon erreur.

CookieSpirit.
« Modifié: Juin 29, 2013, 10:09:01 pm par CookieSpirit »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [TCP/Packets] Problème de transmission de données.
« Réponse #1 le: Juin 29, 2013, 03:10:45 pm »
On dirait (je n'ai pas lu tout le code) que tu accumules toujours ce que tu envoies dans le même paquet, plutôt que d'en utiliser un nouveau à chaque fois. De manière générale, la présence d'un sf::Packet dans les membres d'une classe est un indicateur qu'il y a une erreur de logique : c'est une classe qui est destinée à être utilisée de manière temporaire, pour transformer les données à envoyer. Un paquet n'a pas vocation à être permanent -- dans ce cas il faut au moins le vider avant chaque nouvel envoi.
Laurent Gomila - SFML developer

CookieSpirit

  • Newbie
  • *
  • Messages: 4
    • Voir le profil
Re : [TCP/Packets] Problème de transmission de données.
« Réponse #2 le: Juin 29, 2013, 03:16:16 pm »
Merci beaucoup pour la réponse éclair  ;D

J'ai directement testé en appelant la fonction clear() de la classe packet avant de le remplir à nouveau et de l'envoyer mais le résultat est exactement le même. Quand à en créer un nouveau à chaque fois, c'est à dire que je le déclare directement dans la fonction?
(Je suis assez novice en programmation réseau même si je pense commencer à savoir comment ça fonctionne :-\)

Edit : J'ai laissé tourner l'appli et miracle, au bout d'une trentaine de secondes la position affichée est la bonne, c'est déjà ça mais dans un jeu 30 secondes c'est assez compliqué  ;D
« Modifié: Juin 29, 2013, 03:23:11 pm par CookieSpirit »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [TCP/Packets] Problème de transmission de données.
« Réponse #3 le: Juin 29, 2013, 05:02:02 pm »
Citer
Quand à en créer un nouveau à chaque fois, c'est à dire que je le déclare directement dans la fonction?
Oui.

Sinon désolé mais ton code est un peu long. Si tu arrivais à nous en montrer une version minimal (mais toujours complète), focalisée uniquement sur le problème, ça nous aiderait beaucoup (et toi aussi d'ailleurs -- il est toujours plus simple de trouver un problème dans 20 lignes de code que dans 200).
Laurent Gomila - SFML developer

CookieSpirit

  • Newbie
  • *
  • Messages: 4
    • Voir le profil
Re : [TCP/Packets] Problème de transmission de données.
« Réponse #4 le: Juin 29, 2013, 06:46:28 pm »
Encore merci de la réponse, et de votre considération envers mon problème  :)

J'essaierai de tester la déclaration dans la fonction ainsi qu'un code minimal d'exemple pour pouvoir cibler le problème (Même si le code actuel est très basique et permet juste l'échange de données entre deux clients par le biais d'un serveur).

CookieSpirit

  • Newbie
  • *
  • Messages: 4
    • Voir le profil
Re : [TCP/Packets] Problème de transmission de données.
« Réponse #5 le: Juin 29, 2013, 10:08:47 pm »
Après de nombreux std::cout un peu partout chez le client et le serveur j'ai remarqué que tout allait bien, mais qu'au plus je rajoutais du code dans l'application serveur au plus la synchronisation se faisait.

Synchronisation... j'aurais dû y penser plus tôt, le serveur n'avait pas de limite de framerate, j'ai mis à 60fps à coup de sf::Clock et miracle, tout fonctionne à merveille ! (un décalage d'une seconde se fait sentir mais je me doute que c'est la faute a mon inexpérience en réseau ou au TCP, ou un peu des deux ::) )

J'ai honte de ne pas y avoir pensé plus tôt, et je vous remercie pour l'aide, pour m'avoir fait chercher et surtout pour cette superbe bibliothèque  ;D

Bonne fin de soirée  :)
« Modifié: Juin 29, 2013, 10:32:06 pm par CookieSpirit »

 

anything