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

Auteur Sujet: Avoir "en même temps" un serveur et un client dans le même pgm qui se parlent  (Lu 3915 fois)

0 Membres et 1 Invité sur ce sujet

Rick_Cplusplus

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
    • E-mail
Bonjour la communauté,

Dans ma classe Serveur, j'ai une fonction qui lance le listener,
Dans ma classe Client, j'ai une fonction qui demande une connexion au serveur.

Le pb, (sans doute "classique") c'est que si dans le même programme je lance l'une de ces fonctions, elle garde la main en attendant  l'autre qui du coup n'arrive jamais puisque le pgm est en attente... J'ai essayé de passer les sockets en mode "non blocking" mais cela ne semble pas remédier à la situation.  (si ce n'est pas clair, je peux présenter les codes. ;) )

Je voudrais éviter le multi-threading juste pour ça (le pgm n'en a pas besoin par ailleurs).
Existe-il une idée rusée pour que la socket "locale" puisse appeler le serveur lorsque celui-ci attend en mode listener ?

Sinon, je pense modifier la fonction d'appel de connexion pour le cas particulier de la socket "locale" et l'ajouter au selecteur et son pointeur au vector listant les pointeurs sur les socket en passant son adresse ainsi :

dans Server.cpp
code supprimé pke toufo ^^
 

dans Client.cpp (avec include de serveur.h dans client.h et &serveur passé argument de la fonction)
code supprimé pke toufo ^^
 

Un tel code visant donc :
- à connecter la socket locale au serveur,
- à ajouter la socket locale au selecteur du serveur et
- à ajouter son pointeur au vector listant les pointeurs sur les socket connectées
fonctionnerait-il? ::)

Merci de m'avoir lu,
Rick.
« Modifié: Septembre 06, 2018, 09:33:07 pm par Rick_Cplusplus »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Laisse tomber ta solution de code spécifique pour gérer la socket locale. De toute façon il y a plein d'erreurs dedans ;D

Pour que ton serveur et ton client tournent en parallèle, si tu veux éviter d'avoir 2 threads, passer tout (y compris le listener bien entendu) en non-bloquant devrait être suffisant. Quel problème avais-tu avec cette solution ?
Laurent Gomila - SFML developer

Rick_Cplusplus

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
    • E-mail
Bonjour la communauté,

Citer
Quel problème avais-tu avec cette solution ?

J'ai sans doute mal codé (niveau faux débutant) mais même avec les isBlocking(false) sur la socket client ET listener, cela ne fonctionne pas.

serveur.cpp
#include "../Header_perso/Serveur.h"

//constructeur
Serveur::Serveur(unsigned int Joueurs, unsigned short int Port, bool bloquer)
{
    nbJoueurs=Joueurs;
    port=Port;
    allo.setBlocking(bloquer);
}

// methodes

//Lancement serveur et chargement vector socket de joueurs
bool Serveur::lancement()
{
    if (allo.listen(port) != sf::Socket::Done)
    {
        // erreur...
        std::cout << "port inécoutable" << std::endl;
        return false;
    }
    else // serveur lancé
    {
        selecteur.add(allo);
        std::cout << "Allo ? J'ecoute le port : " << port << std::endl;
        std::cout << "J'attends " << nbJoueurs << " joueur(s)." << std::endl;
    }

    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 std::unique_ptr (accessible depuis C++14)
            auto joueur = std::make_unique<sf::TcpSocket>();

            //  obtention du "pointeur sous-jacent" (le sf::TcpSocket * )
            if (allo.accept(*(joueur.get()) ) == sf::Socket::Done)
            {
                //déréférencement du pointeur renvoyé par la fonction get par *(.get())
                selecteur.add(*(joueur.get()));
                // utilisation de la version de push_back avec std::move
                V_joueur.push_back(std::move(joueur));
            }
            if (V_joueur.size() == nbJoueurs) tousPresents=true;
        }
    std::cout << "nos " << nbJoueurs << " joueur(s) est(sont) connecté(s) sur le serveur." << std::endl;
    std::cout << "V_Joueur size = " << V_joueur.size() << std::endl;
    return true;
}
 

Client.cpp
#include "../Header_perso/Client.h"

//constructeur
Client::Client(std::string adresse, unsigned short int Port, bool bloquer)
{
    adrIp=adresse;
    port=Port;
    socket.setBlocking(bloquer);
}

//méthodes

//  Demande connexion serveur
bool Client::rejoindre()
{
    std::cout << "Demande la connexion au serveur" << std::endl;
    sf::Socket::Status statut = socket.connect(adrIp, port);
    if (statut != sf::Socket::Done) return false;
    std::cout << "connexion établie avec serveur sur port : " << port << " adresse Ip locale : " << adrIp << std::endl;
    return true;
}
 

main.cpp
#include "../../Header_perso/Serveur.h"
#include "../../Header_perso/Client.h"

int main()
{
    bool connecte(false);
    bool serveurLance(false);
    unsigned int nbJoueurs(1);
    unsigned short int port(56000);
    std::string adrIp="192.168.1.14";

    Serveur serveur(nbJoueurs, port, false);
    Client joueur(adrIp, port, false);

    while(!connecte)
    {
        if(!joueur.rejoindre())
        {
            system("cls");
            std::cout << "pas connecte au serveur" << std::endl;
        }
        else
        {
            system("cls");
            std::cout << "connecte au serveur" << std::endl;
        }
        if (!serveurLance)
        {
            if(!serveur.lancement())
            {
                std::cout << "serveur planté" << std::endl;
                return -1;
            }
        serveurLance=true;
        std::cout << "serveur opérationnel" << std::endl;
        }
    }
return 0;
}
 

C'est agaçant parce que j'ai l'intuition que c'est un cas hyper courant mais je ne trouve pas comment faire... Bousk sur développer.com suggère de déclarer la socket locale dans la classe serveur et de la "passer" ensuite dans la classe client (l'inverse de ce que je pensais faire en fait) mais je ne vois pas ce que "passer" veut dire en l’occurrence ni quelle syntaxe utiliser...  :-\

Une suggestion ?
Rick.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Citer
J'ai sans doute mal codé (niveau faux débutant) mais même avec les isBlocking(false) sur la socket client ET listener, cela ne fonctionne pas.
Parce que c'est l'architecture de ton code qui est à revoir complètement. Changer une option sur les sockets ne t'aidera pas à ce niveau là. Ton listener est non-bloquant mais tu l'utilises dans une boucle qui ne sort que lorsque tout le monde est connecté, donc le résultat c'est que ta fonction Serveur::lancement() est toujours bloquante. Pareil pour Client, tu as passé la socket en non-bloquant mais tu n'as pas changé ta manière de l'utiliser.

Prend un peu de recul sur ton architecture de code et demande toi comment tout ça aurait bien pu s'exécuter en parallèle. Et ensuite revois tout pour que ce soit le cas ;)

Citer
*(joueur.get())
Pareil que *joueur.
Laurent Gomila - SFML developer

Rick_Cplusplus

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
    • E-mail
Merci Laurent,

Bon, c'est parti pour une refonte totale !  ;D
Je reviendrai proposer mon résultat.
*senvabosserletruc

Rick.