IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Boost C++ Discussion :

[ASIO] Problème de socket


Sujet :

Boost C++

  1. #1
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut [ASIO] Problème de socket
    Bonjour à tous,

    je développe une application orientée P2P, et j'essaye de créer des noeuds à l'aide de boost ASIO. Je travaille sur une machine virtuelle VMWare (CentOS 5) sur laquelle j'ai déclaré 3 interfaces réseau comme suit:
    eth0: 192.168.0.10
    eth1: 192.168.0.11
    eth2: 192.168.0.12

    Je lance ensuite 3 fois mon application, chacune écoutant sur une interface différente (donné par argument)

    Jusque là, tout fonctionne bien, quand je fais un netstat après le lancement de mes 3 applis, j'ai bien mes 3 interfaces en LISTEN sur le port souhaité:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    tcp        0      0 192.168.0.12:7171           *:*                         LISTEN      
    tcp        0      0 192.168.0.11:7171           *:*                         LISTEN 
    tcp        0      0 192.168.0.10:7171           *:*                         LISTEN
    Je lance ensuite une recherche à partir de la première instance du programme (celui qui écoute en .0.10), pour qu'il essaye de se connecter au 2 autres via leur port d'écoute. La connexion (asynchrone) réussit, mais quand je regarde le socket de la connexion, j'obtiens ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    tcp        0      0 192.168.0.11:39890          192.168.0.11:7171           ESTABLISHED 
    tcp        0      0 192.168.0.11:7171           192.168.0.11:39890          ESTABLISHED 
    tcp        0      0 192.168.0.12:7171           192.168.0.12:47724          ESTABLISHED 
    tcp        0      0 192.168.0.12:47724          192.168.0.12:7171           ESTABLISHED
    Je n'ai donc pas de lien 10/11 et 10/12, mais à la place 11/11 et 12/12...
    Voici le code que j'utilise pour la connection:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void nvsnode::connect(tcp::endpoint& endpoint)
    {
        connec* new_node= new connec(m_io_serv);
        new_node->getSocket().async_connect(endpoint,
                                            boost::bind(&nvsnode::handle_connect, this,
                                                    new_node,
                                                    boost::asio::placeholders::error)
                                           );
    }
    D'ou peut provenir le problème,
    de la configuration de mes interfaces via VMWare?
    de mon code?
    d'une option pour spécifier l'interface de connection dans asio?
    un paramètrage spécial de CentOS?

    Merci de votre attention.

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 35
    Par défaut
    Bonjour Raz-X,

    Lorsque tu dis :
    Citation Envoyé par Raz-X Voir le message
    Je lance ensuite une recherche à partir de la première instance du programme (celui qui écoute en .0.10), pour qu'il essaye de se connecter au 2 autres via leur port d'écoute. La connexion (asynchrone) réussit, mais quand je regarde le socket de la connexion, j'obtiens ceci :
    Comment lances tu cette recherche ? Tu envoies une commande à ta première instance ? Tu utilises une autre application ? Car dans le code que tu as posté on ne voit pas la manière dont tu appelles ta fonction permettant de te connecter aux deux autres instances, je pense qu'il nous faudrait un petit peu plus de code afin de pouvoir t'aider à résoudre ton problème car on ne voit pas les arguments que tu passes à ta fonction.

    Cordialement
    Matarc

  3. #3
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut
    C'est assez simple.
    Au lancement de mon appli, je déclare un io_service, et je démarre un thread spécial pour les échanges réseaux de mon noeud (via un io_service.run())

    Le noeud connaît son interface sur laquelle il doit écouter (donnée en paramètre au lancement de l'appli) ainsi que le port par défaut (ici 7171). Je possède aussi une classe connec, qui représente chacune des connexions que je possède avec les autres noeuds.

    La classe connec possède simplement un tcp::socket (pour le moment) qui est passé en paramètre lors de tentatives de connexion du noeud vers les autres.

    J'initialise mon noeud comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    nvsnode::nvsnode(boost::asio::io_service& io_service,std::string ip,int port)
        :m_io_serv(io_service),
    //interface+port d'acoute
         m_listening_endpoint(boost::asio::ip::address::from_string(ip), port),
    //l'acceptor qui s'y connecte
         m_acceptorV4(io_service,m_listening_endpoint)
    {
    }
    par la suite, je lance une méthode startNode, qui elle même démarre tout d'abord l'écoute sur l'interface spécifiée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void nvsnode::startAcceptNodes()
    {
        connec* new_node= new connec(m_io_serv);
        m_acceptorV4.async_accept(new_node->getSocket(),
                                  boost::bind(&nvsnode::handle_accept,
                                              this,
                                              new_node,
                                              boost::asio::placeholders::error));
        std::cout<<"Start listening new nodes on "<< m_acceptorV4.local_endpoint()<<std::endl;
    }
    Puis quand cela est terminé, tente de se connecter aux 2 autres noeuds via cette méthode:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    void nvsnode::connectSuperNodes()
    {
        // On récupère la liste des SuperNodes pour s'y connecter
        boost::asio::ip::tcp::resolver resolver(m_io_serv);
        boost::asio::ip::tcp::resolver::query query("nodes.appli.local", "7171");
        boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query);
        boost::asio::ip::tcp::resolver::iterator end
     
        while (iter != end) // Pour chaque SuperNode
        {
            boost::asio::ip::tcp::endpoint endpoint = *iter++;
            if(endpoint.address().to_string().compare(m_listening_endpoint.address().to_string())!=0)
            {
                std::cout <<"Connexion au SuperNode "<< endpoint << std::endl;
                try{
                    connect(endpoint);
                }catch(const std::exception & e){
                    std::cout<<"ERREUR: "<< e.what() <<std::endl;
                }
            }
        }
    }
     
    void nvsnode::connect(tcp::endpoint& endpoint)
    {
        connec* new_node= new connec(m_io_serv);
        new_node->getSocket().async_connect(endpoint,
                                            boost::bind(&nvsnode::handle_connect, this,
                                                    new_node,
                                                    endpoint.address().to_string(),
                                                    boost::asio::placeholders::error)
                                           );
        std::cout<<"Connexion à: "<<endpoint<<" avec socket: "<<new_node->getSocket().local_endpoint()<<std::endl;
    }
    Voilà, vous savez tout ^^
    PS: Ce n'est pas très propre ni très évolué, j'essaye pour le moment de comprendre le pourquoi du comment. Je suis allé demander sur l'IRC de boost, et selon eux, cela vient plutôt du fait que j'utilise 3 interfaces sur la même machine, au lieux de 3 machines avec 1 interface chacune...

    Je vais tester ça en attendant, et voir si le problème persiste.
    Si vous avez des suggestions n'hésitez pas.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 35
    Par défaut
    Bonjour,

    Je ne pense pas que ça vienne de là mais sait-on jamais, pourrais tu nous montrer le contenu du fichier /etc/hosts ? La classe query va apparement chercher les noms d'host dans ce fichier.

    Cordialement
    Matarc

  5. #5
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut
    Voici le contenu de /etc/hosts
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    # Do not remove the following line, or various programs
    # that require network functionality will fail.
    127.0.0.1		localhost.localdomain localhost
    ::1		localhost6.localdomain6 localhost6

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 35
    Par défaut
    Citation Envoyé par Raz-X Voir le message
    Voici le contenu de /etc/hosts
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    # Do not remove the following line, or various programs
    # that require network functionality will fail.
    127.0.0.1		localhost.localdomain localhost
    ::1		localhost6.localdomain6 localhost6
    Euh quelque chose m'intrigue là pourrais tu vérifier que tu rentres bien dans la boucle dans la fonction ci-dessous, en affichant un message à l'écran par exemple ?

    Citation Envoyé par Raz-X Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    void nvsnode::connectSuperNodes()
    {
        // On récupère la liste des SuperNodes pour s'y connecter
        boost::asio::ip::tcp::resolver resolver(m_io_serv);
        boost::asio::ip::tcp::resolver::query query("nodes.appli.local", "7171");
        boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query);
        boost::asio::ip::tcp::resolver::iterator end
     
        while (iter != end) // Pour chaque SuperNode
        {
            boost::asio::ip::tcp::endpoint endpoint = *iter++;
            if(endpoint.address().to_string().compare(m_listening_endpoint.address().to_string())!=0)
            {
                std::cout <<"Connexion au SuperNode "<< endpoint << std::endl;
                try{
                    connect(endpoint);
                }catch(const std::exception & e){
                    std::cout<<"ERREUR: "<< e.what() <<std::endl;
                }
            }
        }
    }
     
    void nvsnode::connect(tcp::endpoint& endpoint)
    {
        connec* new_node= new connec(m_io_serv);
        new_node->getSocket().async_connect(endpoint,
                                            boost::bind(&nvsnode::handle_connect, this,
                                                    new_node,
                                                    endpoint.address().to_string(),
                                                    boost::asio::placeholders::error)
                                           );
        std::cout<<"Connexion à: "<<endpoint<<" avec socket: "<<new_node->getSocket().local_endpoint()<<std::endl;
    }

  7. #7
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut
    Je viens de tester, cela fonctionne, je rentre correctement dans la boucle, et je fais bien 2 connec (1 pour 0.11, et l'autre pour 0.12)

    La zone DNS que j'ai déclaré contient uniquement mes 3 interfaces en 10 11 et 12. Globalement tout fonctionne correctement, mais c'est l'attribution des sockets qui est très étrange.

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 35
    Par défaut
    Petite question bête, tu as bien pensé à appeler la méthode run() de ton io_service après l'attente de connexion et la tentative de connexion ?

  9. #9
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut
    Je ne pense pas avoir besoin de relancer io_service::run().

    La fonction que mon thread lance fait ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    cout<<"Start NVS Thread"<<endl;
        MainNode->startNode();
        io_serv.run();
        cout<<"Close NVS Thread"<<endl;
    Dans mon programme, "Start NVS Thread" s'affiche bien au tout début, suivi des différentes configurations, lancement de l'écoute, et les connexions.

    "Close NVS Thread" n'apparaît pas, car il reste toujours du travail asynchrone à réaliser. Je relance en effet toujours une écoute quand j'ai reçu la demande de connexion d'un nouveau noeud. Cela est donc normal je pense.

    Dois-je faire un run() à chaque fois que je tente une connexion? Cela me semble étrange, de tous les exemples que j'ai vu, on n'utilise qu'une unique fois cette méthode (voir tuto gwenael dunand sur developpez).

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 35
    Par défaut
    Non justement selon moi tu dois le faire après toutes tes tentatives de connections, mais comme il n'apparaissait nul part dans le code que tu as donné j'ai préféré être sûr que tu pensais bien à l'appeler. Je suppose que ta fonction membre startNode() fait appel à startAcceptNodes() puis à connectSuperNodes() ?

    Autre chose tu lances bien tes applications en écoutant d'abord sur .12 puis sur .11 et enfin sur .10 ?

    Cordialement
    Matarc

  11. #11
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut
    Citation Envoyé par Matarc Voir le message
    Je suppose que ta fonction membre startNode() fait appel à startAcceptNodes() puis à connectSuperNodes() ?
    C'est exactement ça, j'initialise le tout, je prépare mes connexions, et je fais run().

    Citation Envoyé par Matarc Voir le message
    Autre chose tu lances bien tes applications en écoutant d'abord sur .12 puis sur .11 et enfin sur .10 ?
    Le but de l'application est que les 3 noeuds se connaissent dès qu'un nouveau arrive. Exemple:

    Je lance appli1 sur 0.10: Il cherche 11 et 12, ne les trouve pas (pas encore lancés)
    Je lance appli2 sur 0.11: Il cherche 10 et 12, trouve seulement 10, se connecte à lui. appli1 est alors connecté à appli2.
    Je lance appli3 sur 0.12: Il cherche 10 et 11, les trouve, et se connecte à eux en lançant deux "async_connect" distincts.

    Ainsi, les 3 se connaissent, peu importe l'ordre d'arrivée des noeuds sur le réseau. A leur arrivée, les noeuds lancent toujours une écoute sur leur interface sur un port fixe, pour être prêts à entendre et accepter les nouveaux noeuds qui arriveront par la suite. C'est toujours un nouveau noeud qui a la responsabilité de trouver et de se connecter au noeuds déjà présents.

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 35
    Par défaut
    Là j'avoue que je sèche...
    Tes messages "Connexion au SuperNode 192.168.0.XX" et "Connexion à: 192.168.0.XX avec socket: 192.168.0.XX" s'affichent bien ?

  13. #13
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut
    Oui, ils s'affichent correctement, et me donnent les mêmes résultats que la commande netstat, par exemple, si je lance dans l'ordre 11, 12 puis 10 et que je regarde 10:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Start NVS Thread
    Start listening new nodes on 192.168.0.10:7171
    Connexion au SuperNode 192.168.0.11:7171
    Connexion à: 192.168.0.11:7171 avec socket: 192.168.0.11:53549
    Connexion au SuperNode 192.168.0.12:7171
    Connexion à: 192.168.0.12:7171 avec socket: 192.168.0.12:55022
    -> Connexion réussie à 192.168.0.12
    -> Connexion réussie à 192.168.0.11
    Donc techniquement cela fonctionne correctement, mais il me semble que les adresses des sockets ne sont pas bonnes du fait que les 3 interfaces sont en fait reliés sur la même machine, et que peut-être la couche ip de mon système voit cela, et prend la décision d'attribuer la même adresse...

    Je vais essayer la même appli entre 2 machines virtuelles différentes, on verra bien si cela est différent ou non.

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Mars 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2006
    Messages : 35
    Par défaut
    Citation Envoyé par Raz-X Voir le message
    Donc techniquement cela fonctionne correctement, mais il me semble que les adresses des sockets ne sont pas bonnes du fait que les 3 interfaces sont en fait reliés sur la même machine, et que peut-être la couche ip de mon système voit cela, et prend la décision d'attribuer la même adresse...

    Je vais essayer la même appli entre 2 machines virtuelles différentes, on verra bien si cela est différent ou non.
    Je trouve ça plutôt bizarre mais bon je ne suis pas un spécialiste du réseau alors je ne peux pas affirmer que ça ne vienne pas de là.

    Tiens nous au courant après avoir testé entre deux machines virtuelles différentes.

    Cordialement
    Matarc

  15. #15
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2011
    Messages
    66
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Avril 2011
    Messages : 66
    Par défaut
    Voilà, j'ai lancé mes deux machines virtuelles, voici la config (simplifiée):
    Machine 1:
    -eth0: 192.168.0.10
    Machine 2:
    -eth0: 192.168.0.20

    Je lance mon programme sur les 2 machines, en écoutant respectivement sur le port 7171 en 0.10 et 0.20. La connexion fonctionne, et voici les résultats netstat:
    Machine 1:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    tcp        0      0 192.168.0.10:7171           *:*                         LISTEN           
    tcp        0      0 192.168.0.10:7171           192.168.0.20:38433          ESTABLISHED
    Machine 2:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    tcp        0      0 192.168.0.20:7171           *:*                         LISTEN       
    tcp        0      0 192.168.0.20:38433          192.168.0.10:7171           ESTABLISHED
    La liaison socket est faite, mais quelque chose me perturbe. Dans le protocole socket, il me semble que lorsqu'on écoute sur un port (dans mon cas 7171) et qu'on récupère une demande de connexion, on accepte sur un NOUVEAU socket retourné par la fonction accept(). Or dans mon cas, la socket utilisée est sur le port d'écoute (7171) ce qui me semble étonnant.

    Est-ce une spécificité du mode asynchrone?

Discussions similaires

  1. Asio : problèmes de socket fermé
    Par Kernald dans le forum Boost
    Réponses: 3
    Dernier message: 15/01/2009, 22h42
  2. Problême de Socket avec un applet java (RMI/policy)
    Par Vesperal dans le forum API standards et tierces
    Réponses: 3
    Dernier message: 12/04/2006, 12h00
  3. Réponses: 2
    Dernier message: 26/03/2004, 09h15
  4. [Kylix] Problème de socket
    Par RaygKross dans le forum EDI
    Réponses: 1
    Dernier message: 01/03/2004, 19h41
  5. Mysql ne se lance pas problème de socket
    Par Riko dans le forum Installation
    Réponses: 5
    Dernier message: 05/02/2004, 09h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo