Forum de la communauté SFML

Aide => Réseau => Discussion démarrée par: Rick_Cplusplus le Septembre 03, 2018, 07:20:22 pm

Titre: [Résolu] le selector ne lit pas une socket qui envoie un packet
Posté par: Rick_Cplusplus le Septembre 03, 2018, 07:20:22 pm
Bonjour la communauté,

Avant de vous fournir mon code, je met le contexte :

Le serveur doit attendre la connexion d'un nombre précis de clients (2 à 7).
 => pour se faire j'utilise un "listener", chaque nouvelle socket est indexée dans un vector, et ajoutée à un selector.
Note je n'ajoute pas le listener au selector puisque le nombre de client atteint, aucune autre connexion ne doit s'ajouter.

Lorsque le nombre est atteint, les échanges serveurs / client peuvent commencer.
=> sur le serveur, utilisation de selector "wait" et boucle "for" sur le vector pour déterminer la socket concernée, puis réception du packet
=> sur le client, socket send packet dès que la connexion est établie.

je lance le serveur en débug et le client en release. impossible de voir le selector quitter le "wait" et lancer la lecture du vector (comme si le packet n'était pas envoyé par le client...) Je sèche  ???

ci dessous le code serveur minimal (pour le test je n'attend qu'un seul client):
#include <iostream>
#include <vector>
#include <SFML/Network.hpp>

using namespace std;

int main()
{
    unsigned int nbJoueurs(1); // un seul client pour le test

    // vector pour stocker les socckets des joueurs
    std::vector <sf::TcpSocket*> V_client;

    // declaration du socket (allo) de l'écouteur
    sf::TcpListener allo;

    //Declaration d'un selecteur de socket
    sf::SocketSelector selecteur;

    // affectation au port (breton 56 ^^) à écouter
    unsigned short int port=56000;
    if (allo.listen(port) != sf::Socket::Done)
    {
         // erreur...
        std::cout << "port inécoutable" << std::endl;
        return -1;
    }
    else std::cout << "Allo ? J'ecoute le port 56000" << std::endl; // serveur lancé

    bool tousPresents(false); // passe à true si tous les joueurs ont un socket attitré

    // boucle de surveillance et connexion des joueurs attendus
    while(!tousPresents)
    {
        // déclaration d'un socket à affecter au prochain client qui le demande
        sf::TcpSocket joueur;
        if (allo.accept(joueur) == sf::Socket::Done)
        {
            V_client.push_back(&joueur);
            selecteur.add(joueur);
        }
        if (V_client.size() == nbJoueurs) tousPresents=true;
    }
    std::cout << "nos " << nbJoueurs << " joueurs sont connectés sur le serveur." << std::endl;
    std::cout << "V_client size = " << V_client.size() << std::endl;

    //boucle d'échange de données
    sf::Packet paquet;
    sf::Int32 x(0);
    bool flag(false);
    while(!flag)
    {
        //boucle d'attente de message
        if (selecteur.wait()) // <= c'est là que ça semble foirer...
        {
            for(unsigned int i(0); i<V_client.size(); i++)
            {
                if (selecteur.isReady(*V_client[i]))
                {
                    V_client[i]->receive(paquet);
                    paquet >> x;
                    std::cout << "paquet reçu ; x vaut : " << x << endl;
                    if (x==-1) flag=true;
                    x=-10;
                    paquet << x;
                    system("pause");
                    V_client[i]->send(paquet);
                }
            }
        }
    }
    return 0;
}
 

et le code client :
#include <iostream>
#include <SFML/Network.hpp>

using namespace std; // DSL...

int main()
{
    sf::Int32 x = 10;
    unsigned short int port(56000);
    bool flag(false);
    sf::TcpSocket socket;
    sf::Socket::Status statut = socket.connect("192.168.1.14", port); // Ipv4 locale du serveur
    if (statut != sf::Socket::Done)
    {
        return -1;
    }
    else
    {
        std::cout << "connexion établie sur port " << port << std::endl;
        sf::Packet paquet;
        paquet << x;
        if (socket.send(paquet)!= sf::Socket::Done)
        {
            std::cout << "erreur d'envoi de paquet" << std::endl;
            system("pause");
        }
        while (!flag)
        {
         // pour patienter
        }
        return 0;
}

 

Je devrais recevoir le packet et en extraire x qui vaudrait 10, mais non...  :-\
Une piste ?

Rick.
Titre: Re: le selector ne lit pas une socket qui envoie un packet
Posté par: Laurent le Septembre 03, 2018, 08:37:53 pm
Côté serveur, tu ajoutes dans ton vecteur des adresses de sockets qui n'existeront plus, puisqu'elles sont déclarées localement dans la boucle while.
Titre: Re: le selector ne lit pas une socket qui envoie un packet
Posté par: Rick_Cplusplus le Septembre 03, 2018, 09:38:34 pm
Merci Laurent pour ce retour rapide.

De ta réponse je déduis que le client n'est pas en cause.  ;)

Côté serveur donc, comme hélas les pointeurs et moi sommes fâchés, j'ignorais que les adresses de socket avaient une porté limitée à la boucle ou elle sont déclarées...

Existe-t-il un moyen sioux d'étendre la porté de ces adresses ou suis-je condamné à ne JAMAIS sortir de la boucle while si je veux faire fonctionner les échanges clients / serveur ?

Et dans le second cas, cela veut sans doute dire que TOUT le reste de mon programme devra AUSSI s’insérer dans la boucle while via (j'espère) des appels de fonctions, isn't it ?

Si oui, GROS boulot ahead apparemment... :P

Rick.
Titre: Re: le selector ne lit pas une socket qui envoie un packet
Posté par: Laurent le Septembre 04, 2018, 08:09:28 am
Citer
De ta réponse je déduis que le client n'est pas en cause.
Non, c'est juste que je me suis arrêté à la première erreur que j'ai trouvée. Je n'ai pas regardé le code du client.

Citer
Côté serveur donc, comme hélas les pointeurs et moi sommes fâchés, j'ignorais que les adresses de socket avaient une porté limitée à la boucle ou elle sont déclarées...
Ce ne sont pas les adresses qui ont une portée limitée, mais les variables desquelles tu prends l'adresse. En l'occurence ta variable sf::TcpSocket joueur, qui n'existe pas en dehors du bloc d'accolade qui la contient.

Citer
Existe-t-il un moyen sioux d'étendre la porté de ces adresses
L'allocation dynamique.
Titre: Re: le selector ne lit pas une socket qui envoie un packet
Posté par: Rick_Cplusplus le Septembre 04, 2018, 10:42:18 am
Encore merci pour ton aide et tes indices.  :)
Alors, est-ce que si je fais un code comme suit,

sf::TcpListener allo;

... // code pour que allo écoute le port 56000

std::vector <sf::TcpSocket*> V_client;
bool tousPresents(false);

while(!tousPresents)
    {
        // déclaration d'un socket à affecter au prochain client qui le demande
        sf::TcpSocket *joueur = new sf::TcpSocket();
        if (allo.accept(joueur) == sf::Socket::Done)
        {
            selecteur.add(*joueur);
            V_client.push_back(joueur);
        }
        if (V_client.size() == nbJoueurs) tousPresents=true;
    }
 

on peut dire que j'ai fait une allocation dynamique et que conséquemment, la variable sf::TcpSocket joueur va perdurer au delà de la boucle while donnant du sens à V_client pour la boucle selecteur wait ?

Il faudra aussi surement placer un delete[] à un moment si je veux éviter la fuite de mémoire (sauf si vector gère ça tout seul ?)
Ça vire au cours sur les pointeurs mais comme les socket ne sont pas copyable, il faut bien en passer par eux non ? :'(

Rick.
Titre: Re: le selector ne lit pas une socket qui envoie un packet
Posté par: Laurent le Septembre 04, 2018, 12:17:46 pm
Oui c'est ça l'idée. Pour éviter les désagréments de l'allocation brute, utilise plutôt std::unique_ptr.
Titre: Re: le selector ne lit pas une socket qui envoie un packet
Posté par: Rick_Cplusplus le Septembre 04, 2018, 01:54:40 pm
Ok je regarde ça. Merci pour ta réactivité.
Sujet clos... pour le moment. :)

Rick.