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

C++ Discussion :

Meilleur facon de recevoir/traiter des paquets


Sujet :

C++

  1. #1
    Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2012
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Services à domicile

    Informations forums :
    Inscription : Juin 2012
    Messages : 41
    Points : 41
    Points
    41
    Par défaut Meilleur facon de recevoir/traiter des paquets
    Bonjour,

    Je fais appel a vous tous pour m'aider a trouver une façon clair et rapide pour établir une connexion, recevoir des paquet et réagir en conséquence.

    Le fait est que plusieurs paquets peuvent êtres envoyés d'un coup, et qu'il n'y a pas moyen de savoir combien de paquets vont arriver exactement.


    En ce qui me concerne j'ai essayé 2 méthodes, chacune est parvenue a une échec :

    La première était de créer une boucle qui recevrait les paquet et les traiterait directement.

    Comme rien ne vaut un exemple simple :

    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
     
    While(connected)
    {
        // réception des données avec recv()
        // Vérification du paquet 
        switch(type de paquet)
        {
              case paquet1 :
                    // On réagit en conséquence
                    // On envoie éventuellement une réponse, si réponse 
                    // est attendue
                    break;
              case paquet2 :
                    // On réagit en conséquence
                    break;
              default :
                    // On réagit en conséquence
                    break;
        }
    }
    Mais cette méthode ne réceptionnait pas tous les paquets, les paquets prenait trop de temps à être traités et donc il y avait certains messages non réceptionnés. Ceci menant à une erreur.

    J'ai donc opté pour une boucle d'écoute (threadée) qui stockerait les paquet dans une variable de type "queue" . A coté de cela j'ai créée une fonction processQueue(), qui se chargerait de vider la queue et traiter les paquets.
    Mais hélas cette fonction aussi était vouée a l'échec. Il y avait souvent acces concurrents a mes variables membres, et les mutex ajoutés pour régler cela ne faisait que ralentir le code, voir le stopper.

    un petit exemple :

    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
     
    listener()
    {
        while(true)
        {
            // Reception des données
            // stockage des données dans une variables queue
        }
    }
    processQueue()
    {
        // Boucle vidant la queue et faisant appel la fonction adéquate en fonction
        // du message
    }
     
    // Et dans le constructeur on gère thread

    Petit moment de répit, vous suivez toujours ??



    Voila ce qui en est de mon coté, je vous pose donc la question a vous : comment feriez vous pour récupérer les paquets ?



    PS : Ceci peut également être vu comme un sondage, je pense d'ailleurs mettre une balise [sondage] dans le titre ?

  2. #2
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Je presume que tu utilises le protocole UDP donc. Si tu n'as pas besoin de vitesse, sache que le protocole TCP permet la reception de tous les paquets dans l'ordre dans lequel ils ont ete envoyes.

    Bref, sinon pour repondre a ta question, si tu utilises effectivement le protocole UDP cela signifie qu'il n'est pas important de recevoir tous les paquets. Par consequent je mettrais le numero du paquet dans les 4 premiers octets puis les infos derriere. Ainsi, si le numero du paquet recu est plus faible que le dernier numero recu, cela signifie qu'il est inutile de traiter l'information qu'il contient.

  3. #3
    Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2012
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Services à domicile

    Informations forums :
    Inscription : Juin 2012
    Messages : 41
    Points : 41
    Points
    41
    Par défaut
    Bonjour,

    Non j'utilise bien le protocole TCP. Mais il se trouve qu'il ne reçois pas tous les paquets . Quand je lance deux recv() de suite, je reçois les deux. Mais quand j'essaie de traiter un paquet entre, je rate systématiquement le paquet d'après, ce qui mène a une erreur 10054 .

    Je suis totalement bloqué depuis 3 jours et je ne comprends pas pourquoi .

    Mon hypothèse était donc que le serveur lançait un send() avant que mon recv() ne soit prêt .

    Voila donc pourquoi j'ai créée ce topic. Comment faites vous, en général pour recevoir une suite de paquet ? (je ne demande pas de code concret mais juste une structure basique si possible, car je ne sais plus quoi faire )

  4. #4
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Bonjour,

    Pourrais-tu nous montrer ton code ?

    Est-ce que tu ne fermerais pas ta connexion pendant que tu traites ton paquet

  5. #5
    Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2012
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Services à domicile

    Informations forums :
    Inscription : Juin 2012
    Messages : 41
    Points : 41
    Points
    41
    Par défaut
    Non la connexion est bien ouverte, le recv() ne fais que attendre un message sans renvoyer d'erreur. D'ailleurs parfois il arrive que le code sois assez rapide et la je reçois le deuxième paquet .

    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
     
     
    #include "network/server.h"
     
    // ################################################
    // ##
    // ##   Configuration de la socket
    // ##   Connexion
    // ##   Destruction
    // ##
    // ################################################
     
    server::server()
    {
        framework = new handler();
        framework->setLogins(usr, pass);
            #if defined (WIN32)
                    erreur = WSAStartup(MAKEWORD(2,2), &WSAData);
            #else
                    erreur = 0;
            #endif
     
        if(!erreur)
        {
            // create socket
            sock = socket(AF_INET, SOCK_STREAM, 0);
     
            // Connection configuration
            sin.sin_addr.s_addr = inet_addr(ip);
            sin.sin_family = AF_INET;
            sin.sin_port = htons(port);
            // If connection
            if(connect(sock, (SOCKADDR*)&sin, sizeof(sin)) != SOCKET_ERROR)
            {
                thread = new pthread_t();
                pthread_create(thread, NULL, StaticThreadFunc, this);
                pthread_join(*thread, NULL);
                starter_check = true;
            }
            else
                starter_check = false;
     
        }
        else
            starter_check = false;
    }
     
     
    server::~server()
    {
            closesocket(sock);
     
            #if defined (WIN32)
                    WSACleanup();
            #endif
     
    }
     
    // ################################################
    // ##
    // ##   Creation de la boucle d'écoute
    // ##   
    // ##
    // ##
    // ################################################
     
    void *server::StaticThreadFunc(void *Param)
    {
        server* Obj = reinterpret_cast<server*>(Param);
        return Obj->listener();
    }
    void* server::listener()
    {
        int ok;
        while(true)
        {
            // Reception des données
            ok = recv(sock, buffer, sizeof(buffer), 0);
            // Vérifier si reception de données
            if(ok == SOCKET_ERROR)
            {
                cout << "error" << endl;
                system("pause");
            }
            processMessage();
        }
    }
    void server::processMessage()
    {
        // Recupération de l'id du paquet
        Id = getId(buffer);
        // Recupération du message & lancement de l'évenement
        framework->process(Id, sock, buffer);
        // La réponse est envoyée dans cette derniere fonction
    }

  6. #6
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Pas tip top ta boucle infinie... Je ferais plutot ca a ta place :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    while((ok = recv(sock, buffer, sizeof(buffer), 0)) > 0)
    {
        processMessage();
    }
    // Vérifier si reception de données
    if(ok == SOCKET_ERROR)
    {
        cout << "error" << endl;
        system("pause");
    }
    Sinon pour ton erreur je vois pas trop d'ou elle pourrait venir a part une deconnexion du serveur...

  7. #7
    Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2012
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Services à domicile

    Informations forums :
    Inscription : Juin 2012
    Messages : 41
    Points : 41
    Points
    41
    Par défaut
    Merci,

    je ne savais pas que l'on pouvais vérifier la réception d'un paquet.

    Pour ce qui est de l'erreur je vais essayer de threader le processMessage()

  8. #8
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Ce ne serait pas tres utile etant donne que ta methode listener est deja threadee. De plus, si tu as recu x octets, et que t'en as lu y, tu pourras toujours en lire x - y octets, donc il est inutile de faire une pile de message (sauf si tu en as une utilite bien precise comme une sorte d'historique par-exemple).

  9. #9
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    Salut,

    je sais pas si c'est encore d'actualité, mais en général, le thread qui reçoit les messages les empile, et c'est dans le main thread qu'on les dépile.
    Pour ça, il faut choisir les bons containers, le vector sera plus délicat à cause des réallocations possible en plein parcours, mais la list (queue ou dequeue) seront aisément utilisables.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  10. #10
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Pour ça, il faut choisir les bons containers, le vector sera plus délicat à cause des réallocations possible en plein parcours, mais la list (queue ou dequeue) seront aisément utilisables.
    Même avec une liste il faut faire attention aux problèmes d'accès concurrent (si tu pop la dernière valeur en même temps que tu en push une nouvelle, en particulier). Il faudra donc soit mettre des mutex pendant les accès à la liste, soit utiliser un conteneur "lock free" comme celui ci (nécessite C++11) : lock free queue (par Herb Sutter).

Discussions similaires

  1. Réponses: 3
    Dernier message: 27/06/2011, 10h28
  2. [MySQL] Meilleure facon d'insérer des données dont certaines peuvent être en double ?
    Par beninsky dans le forum PHP & Base de données
    Réponses: 5
    Dernier message: 15/05/2010, 09h17
  3. [MySQL] Meilleure facon de récupérer des resultats sur une période
    Par beninsky dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 29/03/2010, 15h01
  4. le meilleur langage pour traiter des gros fichiers xml
    Par hansaplast dans le forum XML/XSL et SOAP
    Réponses: 7
    Dernier message: 06/07/2009, 22h35
  5. meilleure facon de gerer des interruptions ?
    Par kamouminator dans le forum Linux
    Réponses: 0
    Dernier message: 20/04/2009, 11h39

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