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

Réseau C Discussion :

Socket, recv et select qui ne marche pas


Sujet :

Réseau C

  1. #1
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 65
    Points : 33
    Points
    33
    Par défaut Socket, recv et select qui ne marche pas
    Bonjour,


    Je réalise une fonction (sous linux) pour améliorer la fonction recv, notamment en gérant les paquet coupé en ethernet et un timeout :
    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
    int recvPaquet(int sock, char *paquet, int longueur)
    {
      int nbRecu = 0, nbRecu2 = 1;
      int retval;
     
      fd_set readfds;
     
      struct timeval timeout;
     
      FD_ZERO(&readfds);
      FD_SET(sock, &readfds);
     
      timeout.tv_sec = TIMEOUT; 
      timeout.tv_sec = 1; 
      timeout.tv_usec = 0;
     
      retval = select(1, &readfds, NULL, NULL, &timeout);
     
      if (retval) {
     
        nbRecu = recv(sock, paquet, longueur, 0);
     
        // On gère le cas ou tous les caracteres voulu ne sont pas arrivées
     
        nbRecu2= nbRecu;
     
        while ((nbRecu > 0) && (nbRecu != longueur) && (nbRecu2 > 0)) {
     
          paquet += nbRecu2;
     
          nbRecu2 = recv(sock, paquet, longueur - nbRecu, 0);
     
          if (nbRecu2 >= 0) {
    	nbRecu += nbRecu2;
          }
          else {
    	nbRecu = nbRecu2;
          }
     
        }
        return nbRecu;
      }
      else {
        printf("recvPaquet %d\n",retval);
        return -1;
     
      }
     
    }
    Seulement retval vaut toujours 0, et la fonction retourne -1. Je ne comprend pas pourquoi.

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    essaie avec sock+1 en tant que premier paramètre de select()...
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 65
    Points : 33
    Points
    33
    Par défaut
    J'ai essayer avec sock+1, la fonction ne retourne plus systématiquement -1. apparement ca marche, je vais appronfondir les tests.
    Merci.

  4. #4
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 65
    Points : 33
    Points
    33
    Par défaut
    J'ai fait la même chose pour la fonction send
    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
     
    int sendPaquet(int sock, char *paquet, int longueurPaquet)
    {
      int nbRecu = 0;
      int retval;
     
      fd_set readfds;
     
      struct timeval timeout;
     
      FD_ZERO(&readfds);
      FD_SET(sock, &readfds);
     
      timeout.tv_sec = TIMEOUT; 
      timeout.tv_sec = 10; 
      timeout.tv_usec = 0;
     
      retval = select(sock+1, &readfds, NULL, NULL, &timeout);
     
      if (retval) {
     
        nbRecu = send(sock, paquet, longueurPaquet, 0);
     
        printf("sendPaquet lg=%d send=%d\n",longueurPaquet,nbRecu);
     
        return nbRecu;
      }
      else {
        printf("sendPaquet ERREUR %d\n",retval);
        return -1;
     
      }
     
    }
    Les octets sont bien envoyés, mais immédiatement après le serveur coupe la communication. Je ne peux plus envoyer ou recevoir de données au serveur. Je voudrais verifier que la communication avec le serveur n'a pas été coupé avant d'envoyer.
    Ceci afin de rendre le send non bloquant.
    Est-ce comme celà que je dois proceder ?

  5. #5
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Zapan
    J'ai fait la même chose pour la fonction recv
    Je ne vois pas de recv()...
    Pas de Wi-Fi à la maison : CPL

  6. #6
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 65
    Points : 33
    Points
    33
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Je ne vois pas de recv()...
    J'ai fais une faute. Je voulais dire : send() au lieu de recv()

  7. #7
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Zapan
    J'ai fais une faute. Je voulais dire : send() au lieu de recv()
    Et tu bloques avec select() sur la reception ? Etrange... Pourquoi as-tu besoin de select() pour l'émission ? send() est synchrone, il n'y a rien à faire de particulier. Tu fais send() et c'est tout.

    http://emmanuel-delahaye.developpez.com/reseaux.htm
    Pas de Wi-Fi à la maison : CPL

  8. #8
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 65
    Points : 33
    Points
    33
    Par défaut
    Non, maintenant je ne bloque pas sur le select.
    J'utilise le select() pour etre sur que le serveur marche. Si il ne marche pas, mon programme essaye d'envoyé des données et reste bloqué.

  9. #9
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 65
    Points : 33
    Points
    33
    Par défaut
    Mon probléme est que le serveur peut planter. Lorsqu'il plante il entraine la fin de mon programme lorsque je fais un send. J'aimerais pourvoir gérer le cas ou le serveur plante.

  10. #10
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Zapan
    Mon probléme est que le serveur peut planter. Lorsqu'il plante il entraine la fin de mon programme lorsque je fais un send. J'aimerais pourvoir gérer le cas ou le serveur plante.
    EDIT Si tu es en mode connecté (TCP/IP), tu dois tester le compte rendu de send().

    Si il fait -1, c'est qu'il ya une erreur dans errno. Les valeus possibles :
    Citation Envoyé par POSIX.1
    ERRORS

    The send() function shall fail if:

    [EAGAIN] or [EWOULDBLOCK]
    The socket's file descriptor is marked O_NONBLOCK and the requested operation would block.
    [EBADF]
    The socket argument is not a valid file descriptor.
    [ECONNRESET]
    A connection was forcibly closed by a peer.

    [EDESTADDRREQ]
    The socket is not connection-mode and no peer address is set.
    [EINTR]
    A signal interrupted send() before any data was transmitted.
    [EMSGSIZE]
    The message is too large to be sent all at once, as the socket requires.
    [ENOTCONN]
    The socket is not connected or otherwise has not had the peer pre-specified.

    [ENOTSOCK]
    The socket argument does not refer to a socket.
    [EOPNOTSUPP]
    The socket argument is associated with a socket that does not support one or more of the values set in flags.
    [EPIPE]
    The socket is shut down for writing, or the socket is connection-mode and is no longer connected. In the latter case, and if the socket is of type SOCK_STREAM, the SIGPIPE signal is generated to the calling thread.

    The send() function may fail if:

    [EACCES]
    The calling process does not have the appropriate privileges.
    [EIO]
    An I/O error occurred while reading from or writing to the file system.
    [ENETDOWN]
    The local network interface used to reach the destination is down.
    [ENETUNREACH]
    No route to the network is present.
    [ENOBUFS]
    Insufficient resources were available in the system to perform the operation.
    Pas de Wi-Fi à la maison : CPL

  11. #11
    Membre averti
    Avatar de joellel
    Profil pro
    Inscrit en
    Février 2003
    Messages
    234
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Février 2003
    Messages : 234
    Points : 338
    Points
    338
    Par défaut
    Ben... Teste le code retour de tes fonctions et fais le traitement approprié...
    Ton programme ne crashera plus

  12. #12
    Nouveau membre du Club
    Inscrit en
    Mai 2004
    Messages
    65
    Détails du profil
    Informations forums :
    Inscription : Mai 2004
    Messages : 65
    Points : 33
    Points
    33
    Par défaut
    Citation Envoyé par Emmanuel Delahaye
    Si tu es en mode connecté (TCP/IP), tu peux surveiller le compte rendu du protocole avec le 4 ème paramètre de select() : exceptfds.

    (je me renseigne pour les détails)
    Je suis connecter en TCP/IP : sock = socket(AF_INET,SOCK_STREAM, 0);

  13. #13
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Zapan
    Je suis connecter en TCP/IP : sock = socket(AF_INET,SOCK_STREAM, 0);
    OK. J'ai modifié mon post...
    Pas de Wi-Fi à la maison : CPL

  14. #14
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 201
    Points : 108
    Points
    108
    Par défaut
    Salut,

    Essaye de mettre ton socket en mode non bloquant. Et rajoute l'option MSG_NOSIGNAL sur ton send.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    nbRecu = send(sock, paquet, longueurPaquet, 0);
     
    // Devient:
     
    nbRecu = send(sock, paquet, longueurPaquet, MSG_NOSIGNAL);
    Voici une fonction qui permettra de mettre, proprement, ton socket en mode non bloquant:

    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
     
    void set_nonblock(int sock) {
     
    	int opts;
     
    	if ((opts = fcntl(sock, F_GETFL)) < 0) {
    		perror("fcntl(F_GETFL)");
    	}
     
    	opts = (opts | O_NONBLOCK);
     
    	if (fcntl(sock, F_SETFL, opts) < 0) {
    		perror("fcntl(F_SETFL)");
    	}
    }
    Utilise cette fonction hors de tes fonctions d'envoi et de réception, par exemple après l'appel à connect() ou accept, bind, etc...

    Pour ce qui est du test d'interruption de la connexion avec le serveur, tu peux faire une boucle infinie dans laquelle le select vérifie qu'il y a des données sur la socket en attente. Si il y en a, alors tu les récupères avec un recv() et s'il retourne -1 c'est que la connexion est rompue. Voilà j'espère que ça t'aidera, je n'ai pas fait de C depuis plus d'un an donc... à confirmer ;)

    EDIT: Trois topics pour un même problème, tu abuses un peu quand même...

  15. #15
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    MSG_NOSIGNAL ?
    C'est un breaking change, de réclamer ce flag pour ne pas faire de crash!
    Comment ont-il OSÉ ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  16. #16
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 201
    Points : 108
    Points
    108
    Par défaut
    Propose une solution alors, et ne commente pas une seule partie du post, quit à critiquer fais le intelligemment et jusqu'au bout.
    En général quand je critique c'est que je peux faire mieux... sinon je m'abstiens.

  17. #17
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Oh, mais ce n'est pas toi que je critique : Ce sont les développeurs de cette API.

    Les serveurs UNIX sur lesquels je compilais autrement, ainsi Windows, ignorent jusqu'à l'existence de ce flag et retournent sagement -1...
    (d'où mon post "mais ce n'est pas un crash, ça, c'est un échec et ça se traite gentiment" : j'ignorait également l'existence d'une telle connerie qui nie tout ce que j'aime dans le langage C et sa bibliothèque standard)

    La fonction pourrait même retourner systématiquement -1 avec EINVAL si on met ce flag sur un système qui ne le connait pas...

    Ce sont tous les nouveaux systèmes unixoïdes qui génèrent cette monstruosité par défaut en cas d'échec ?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  18. #18
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    201
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 201
    Points : 108
    Points
    108
    Par défaut
    Ok autant pour moi..

    Si on utilise ce flag sur un système qui ne le connait pas, alors le programme ne se compilera pas, à moins qu'un header définisse la même constante quelque part, ce qui est peu probable.
    Mais pour ce qui est de la portabilité, il y a de fortes chances pour que ce flag soit restreint aux systèmes UNIX like et *BSD (et encore). Une solution plus portable serait peut-être d'intercepter le signal SIGPIPE pour traiter le comportement du programme différemment.

  19. #19
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par hush
    EDIT: Trois topics pour un même problème, tu abuses un peu quand même...
    Et dans plusieurs forums...
    Pas de Wi-Fi à la maison : CPL

Discussions similaires

  1. [MySQL] INSERT aprés un SELECT qui ne marche pas
    Par mrsoyer dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 06/10/2011, 15h45
  2. readonly dans un select qui ne marche pas sous IE
    Par jules_diedhiou dans le forum Général JavaScript
    Réponses: 9
    Dernier message: 15/03/2009, 13h17
  3. select distinct qui ne marche pas
    Par Baldric de Dol dans le forum Requêtes
    Réponses: 6
    Dernier message: 05/05/2008, 17h16
  4. Select Case qui ne marche pas
    Par Zak Blayde dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 30/07/2007, 13h45
  5. Socket qui ne marche pas
    Par Guillaume602 dans le forum C++
    Réponses: 4
    Dernier message: 15/01/2006, 14h07

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