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

Bibliothèques Discussion :

Winsock2 et TCP/IP, le terrible couple


Sujet :

Bibliothèques

  1. #1
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut Winsock2 et TCP/IP, le terrible couple
    Bonjour,


    Je suis en train de programmer une petite bibliothèque pour simplifier l'utilisation de Windows Socket API avec la suite TCP/IP dans le cadre de mon projet d'études. Toutefois je suis un grand novice en la matière et, bien évidemment, je fais face à quelques problèmes et interrogations concernant cette interface de programmation. J'ai donc décidé de créer ce sujet pour poser toutes mes questions sur le "combo" Winsock2-TCP/IP. Oui, j'ai bien dit "toutes mes questions"!

    Avant de commencer la danse, je tiens à préciser quelques points qui pourront servir par la suite. Tout d'abord, je programme avec Visual C++ 2010 sur Windows 7 et j'utilise la version 2.2 de WSA. Ensuite, j'ai tendance à appeler les sockets qui "se contentent" de guetter les connexions entrantes des "listeners" (à cause de la fonction listen) afin de les distinguer des autres sockets qui servent dans la communication.

    Je propose maintenant d'entrer dans le vif du sujet avec la première question:

    [1] - J'ai dans mon programme un socket connecté à un hôte distant; il s'appelle mySocket. Pour vérifier s'il a reçu des données j'utilise le code ci-dessous.
    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
    struct fd_set rSet;
    struct timeval timeout;
    int iErr;
     
    FD_ZERO(&rSet);
    FD_SET(mySocket, &rSet);
    timeout.tv_sec = 0;
    timeout.tv_usec = 10;
     
    iErr = select((int)mySocket + 1, &rSet, NULL, NULL, &timeout);
    if(iErr == SOCKET_ERROR)
    {
        //ERREUR!
    }
    else if(iErr == 0)
    {
        //Socket toujours connecté; aucune donnée reçue
    }
    else //if(iErr == 1)
    {
        //Soit la connexion a été rompue
        //Soit le socket a reçu des données
    }
    Mon problème se trouve dans le cas où iErr vaut 1. En effet, lorsque l'hôte distant rompt la connexion, mon socket reçoit des données de taille nulle. Ainsi, la fonction FD_ISSET ne m'est d'aucun secours. Y a-t-il un moyen de savoir si la connexion est toujours établie, sans faire appel à la fonction recv? Peut-être via la fonction select, en testant l'éligibilité en écriture du socket ou en vérifiant s'il n'a pas reçu quelque(s) exception(s)?


    Merci d'avance pour votre aide.


    Adishatz!


    PS: Désolé, si j'ai créé ce nouveau sujet dans la mauvaise section.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  2. #2
    Membre actif Avatar de Vespiras
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2012
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2012
    Messages : 168
    Points : 265
    Points
    265
    Par défaut
    Salut,

    Pourquoi tu n'engloberais pas la fonction "recv" dans un if qui testerait la valeur de ton buffer de réception, si != NULL alors tu entres dans recv, sinon, tu affiches "client déconnecté".

    Ca fait belle lurette que j'ai pas fait d'applis client/serveurs en C++ mais je pense que c'est une manière simple de tester, non ?

  3. #3
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    En fait, je voudrais écrire une méthode hasBytesToRead qui vérifie si le socket a reçu des données et je considère, peut-être à tort, que cette méthode ne devrait pas utiliser la fonction recv et donc vider le buffer en lecture. Par ailleurs, le problème que je rencontre ici implique que je dois réécrire la méthode isConnected...
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  4. #4
    Membre actif Avatar de Vespiras
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2012
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2012
    Messages : 168
    Points : 265
    Points
    265
    Par défaut
    Effectivement si tu en fait une méthode, je vais te montrer un exemple de ce que j'avais fait.
    A mon sens, tu as besoin de la méthode recv pour cela, car tu ne peux pas deviner l'état du client sans recevoir son flux. Je dirais plutôt un truc du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int hasBytesToRead(ClientSocket cSock)
    {
        int nBytes;
        unsigned long messageSize;
        nBytes = recv(clientSocket, (char*)&messageSize, sizeof(messageSize), 0);
        if(nBytes ==SOCKET_ERROR || nBytes == 0) return WSAGetLastError();
        // si la valeur de retour est WSAECONNRESET, alors le client à deconnecté, sinon, GROSSE ERREUR
        else return nBytes;
    }
    Ou alors j'ai mal compris pourquoi tu te prends la tête ...

  5. #5
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    J'ai continué mes recherches en parallèle de ce sujet pour trouver une alternative à la fonction bloquante recv: je n'aime pas trop me tourner les pouces. J'ai découvert que la fonction ioctlsocket avec le code FIONREAD pourrait satisfaire mes besoins. Je vais tester ça de mon côté et si je trouve une réponse à mon problème je vous en ferai part.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  6. #6
    Membre actif Avatar de Vespiras
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Décembre 2012
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Décembre 2012
    Messages : 168
    Points : 265
    Points
    265
    Par défaut
    Je ne comprend toujours pas pourquoi tu ne veux pas utiliser recv, car bloquante ou pas, elle te renvoie directement une valeur dès que le client en question est déconnecté. Donc, de toutes manière tu dois obligatoirement attendre un retour du client, que ça soit des données, ou un signal d'interruption de la connexion .

    Ou alors tu veux faire du traitement asynchrone, tout en écoutant le client, mais bon dans ce cas du multi-threading ca va bien aussi

  7. #7
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    Citation Envoyé par Vespiras Voir le message
    [...]
    Ou alors tu veux faire du traitement asynchrone, tout en écoutant le client, mais bon dans ce cas du multi-threading ca va bien aussi
    Je veux pouvoir faire du traitement asynchrone sans forcément avoir recours au multithreading. Alors, certes, ça demande beaucoup de travail en amont et entraîne certaines complications.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  8. #8
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    Je pense avoir trouver la solution de mon problème. Voici le code:
    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
    struct fd_set rSet;
    struct timeval timeout;
    int iErrIoctl, iErrSelect;
     
    FD_ZERO(&rSet);
    FD_SET(mySocket, &rSet);
    timeout.tv_sec = 0;
    timeout.tv_usec = 10;
     
    iErrSelect = select((int)mySocket + 1, &rSet, NULL, NULL, &timeout);
    if(iErrSelect == SOCKET_ERROR)
    {
        //ERREUR!
    }
    else if(iErrSelect == 0)
    {
        //Socket toujours connecté; aucune donnée reçue
    }
    else //ici: iErrSelect == 1
    {
        unsigned long ulRes;
     
        iErrIoctl = ioctlsocket(mySocket, FIONREAD, &ulRes);
        if(iErrIoctl == SOCKET_ERROR)
        {
            //ERREUR!
        }
        else if(ulRes == 0) //ici: iErrIoctl == 0
        {
            //La connexion a été rompue!
        }
        else //ici: (iErrIoctl == 0) && (ulRes > 0)
        {
            //Socket toujours connecté; données reçues
        }
    }
    Alors, lorsque iErrSelect vaut 1, ça veut dire, soit que la connexion a été rompue, soit que le socket a reçu des données de la part de son partenaire. Pour régler cette indécision, j'ai utilisé la fonction ioctlsocket (cf. ligne 23). Si tout se passe bien, c'est-à-dire quand iErrIoctl vaut 0 et non pas SOCKET_ERROR, la variable ulRes renvoie le nombre d'octets pouvant être lus via la fonction recv. Ainsi, si ulRes vaut 0, alors la connexion a été rompue par le socket distant; sinon des données ont été reçues.

    Suivant l'utilisation de cet algorithme optimisable (notamment via la fusion de iErrSelect et iErrIoctl), certaines parties peuvent être élaguées. En revanche, s'il y a mieux je reste preneur...
    ... pourvu que ça me permette de faire de l'asynchrone sans multithreading.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

Discussions similaires

  1. Ping sous protocole TCP (et non UDP)
    Par ovdz dans le forum Développement
    Réponses: 2
    Dernier message: 19/06/2003, 14h10
  2. [socket][tcp] jeu en reseau
    Par souris_sonic dans le forum Développement
    Réponses: 2
    Dernier message: 30/05/2003, 07h31
  3. [Concept]Concept d'un serveur TCP/IP
    Par Zc dans le forum Développement
    Réponses: 8
    Dernier message: 17/01/2003, 17h06
  4. Différence entre TCP, UDP, ICMP
    Par GliGli dans le forum Développement
    Réponses: 1
    Dernier message: 13/09/2002, 08h25
  5. transfert d'un fichier bitmap en socket tcp
    Par localhost dans le forum C++Builder
    Réponses: 5
    Dernier message: 29/07/2002, 00h40

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