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 :

Erreur socket WSAWOULDBLOCK


Sujet :

Réseau C

  1. #1
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    52
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 52
    Par défaut Erreur socket WSAWOULDBLOCK
    Bonjour,

    Je travail actuellement sur une application qui utilisent des sockets non bloquantes pour l'envoie de paquets en UDP.
    L'application reçoit des donné d'un pc du réseau, les traite et les renvoie en UDP (broadcast) pour d'autres ordinateurs.
    Le problème vient du fait que des paquets sont transmis en permanence, mais de temps en temps certains paquets ne sont pas émis (avec l'erreur WSAWOULDBLOCK, avec quelques minutes entres chaque erreur).
    J'ai essayé d'augmenter la taille des buffer d'émission et de réception mais rien n'y fait. L'erreur se produit même sur des paquets de petites taille.

    Auriez-vous une idée permettant de résoudre le problème que je rencontre ?

    Je vous remercie par avance

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Effectivement, WSAWOULDBLOCK indique que ton buffer d'émission est plein. Même avec des petits paquets si tu émets par rafales, cela peut se produire. Quelles solutions? Puisque t'es sur UDP, je dirais que normalement ton protocol applicatif devrait se permettre de se passer de ces packets! Sinon, tu peux toujours gérer ta propre chaîne de buffer d'émission par derrière, mais tu risques de rencontrer le problème un peu plus tard (quand tu ne pourras plus allouer)!

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 787
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 787
    Par défaut
    Avec des sockets non bloquantes, vous pouvez tout à fait demander à transmettre plus de paquets que la pile IP ne sera capable de pousser sur l'interface réseau.

    Avant d'essayer de trouver des solutions, il serait peut être sage de considérer quelque peu la bande passante réseau utilisée par votre application
    • est-ce raisonnable? dans quelles conditions çà déborde?
    • y a-t-il des alternatives? quelles implications?


    Si vous voulez que les paquets soient transmis au moins une fois, il faudra attendre que la pile IP les accepte. Cela pourra ralentir la lecture des requêtes et réguler le flux de bout en bout.

    Note: Bien que vous travailliez en UDP, je suppose que les messages émis sont attendus par les clients. Que se passe-t-il s'ils ne les recoivent pas? Ils re-soumettent le boulot déjà fait?
    Dans ce cas, vous comprendrez que "jeter" des paquets signifie refaire du boulot et donc gaspiller une bande passante qui vous fait déjà défaut.
    -W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    52
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 52
    Par défaut
    Merci pour vos réponses.

    En effet l'application qui reçoit les messages permet de mettre à jour une carte (géographique) avec des éléments dessus. Tant qu'un nouveau message n'est pas reçu, l'affichage n'est pas remis à jour et attend un message pour se rafraichir.
    Ce que j'ai remarqué, c'est lors de ces erreurs WSAWOULDBLOCK, certaines dérèglent mon affichage (suppression d'information, décalage...) et se remettent correctement lors de la réception d'un nouveau paquet. Il me semble donc vu cette constatation, que mon message est émis de manière incorrecte (le message n'est pas complet, il est corrompu...).
    C'est ce problème de saut des informations de ma carte que j'essaie de supprimer, je souhaite donc résoudre ce problème à la source: en éliminant les erreurs d''emission WSAWOULDBLOCK.

    Pour information j'utilise la fonction sendto des winsock2.

    Merci pour votre aide!

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Pour reformuler ce que j'avais dit, à partir du moment où les échanges se font en UDP, cela veut dire qu'il faut savoir gérer la perte de paquets. Donc à mon avis, toute tentative d'intervenir sur les réseau ne fait que décaler un pb potentiel. Il serait plus pertinent de travailler sur l'affichage avec des données moins à jour ou pas tout à fait cohérentes mais que cela reste transparent pour l'utilisateur.

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par damdam78 Voir le message
    Je travail actuellement sur une application qui utilisent des sockets non bloquantes
    Pourquoi non bloquante ? C'est une source d'ennuis bien connue, la preuve.

    Utilise les sockets bloquantes (synchrones) et tu n'auras pas de problèmes de congestion. Si les attentes sont gênantes, utilise un thread par fonction bloquante.

  7. #7
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    52
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 52
    Par défaut
    Je te remercie pour ta réponse, mais en fait nous avons crée un dll qui réalise tout le protocole de connexion et d'envoi/réception des messages pour que ce soit transparents pour les applications qui les utilise.
    Donc pour le moment ce n'est pas possible de modifier le fonctionnement de cette dll.

    Je me demandai s'il est possible de vérifier l'état du buffer du socket avant d'appeler la fonction sendto pour être sûr qu'elle réussisse ?

    Merci

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par damdam78 Voir le message
    Je te remercie pour ta réponse, mais en fait nous avons crée un dll qui réalise tout le protocole de connexion et d'envoi/réception des messages pour que ce soit transparents pour les applications qui les utilise.
    Donc pour le moment ce n'est pas possible de modifier le fonctionnement de cette dll.
    Visiblement, cette DLL est buggée. Il faut la corriger ou en écrire une autre. C'est pas en bricolant à droite à gauche qu'on arrive à quelque chose...

  9. #9
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    52
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 52
    Par défaut
    Citation Envoyé par Emmanuel Delahaye Voir le message
    Visiblement, cette DLL est buggée. Il faut la corriger ou en écrire une autre. C'est pas en bricolant à droite à gauche qu'on arrive à quelque chose...
    C'est bien ce que j'essaie de faire en supprimant les bugs de cette dll.
    Je viens d'essayer la fonction "select". Elle a l'air de fonctionner correctement.
    Par contre cette fonction rend bloquant mon programme.
    Existe-il une fonction du même type que select qui renvoie un code d'erreur disant que le buffer socket en émission est plein et donc qu'une émission n'est pas possible sans rendre mon programme bloquant ?

    Merci

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

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Par défaut
    Citation Envoyé par damdam78 Voir le message
    C'est bien ce que j'essaie de faire en supprimant les bugs de cette dll.
    Je viens d'essayer la fonction "select". Elle a l'air de fonctionner correctement.
    Par contre cette fonction rend bloquant mon programme.
    Existe-il une fonction du même type que select qui renvoie un code d'erreur disant que le buffer socket en émission est plein et donc qu'une émission n'est pas possible sans rendre mon programme bloquant ?
    Il faut vraiment cesser le bricolage.

    Soit tu choisis la facilité (mode synchrone : fonctions bloquantes + threads) et ça marche tant qu'il n'y a pas des milliers de clients à traiter en même temps, soit tu choisis la voie royale (asynchrone : fonctions non bloquantes 'send and forget' et tu apprends à gérer l'asynchronisme correctement, notamment en traitant les évènements de fin d'émission, ce qui permet d'éviter d'émettre trop vite... select() peut aider mais est forcément bloquante (il faut bien attendre les évènements quelque part...).

    C'est un métier...

    Maintenant, si tu me dis que c'est l'application qui a été conçue pour utiliser de travers le mode asynchrone, c'est l'application qu'il faut réécrire... (ou alors c'est à la DLL de sérialiser les demandes avec une liste chainée et de faire des émission synchrones...simple, ou asynchrones... compliqué)

  11. #11
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 787
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 787
    Par défaut
    select accepte le paramètre timeout qui s'il est non null mais avec timeval null doit retourner sans attendre
    If timeout is a non-nil pointer, it specifies a maximum interval to wait
    for the selection to complete. If timeout is a nil pointer, the select
    blocks indefinitely. To effect a poll, the timeout argument should be
    non-nil, pointing to a zero-valued timeval structure.
    Timeout is not
    changed by select(), and may be reused on subsequent calls, however it is
    good style to re-initialize it before each invocation of select().
    Maintenant à quoi cela sert-il d'ajouter des seaux pour amortir le débordement de la pile IP: les affichages auront un retard dont la borne supérieure risque d'être difficile à définir.

    La mémoire du système n'étant pas infinie, le programme risque de planter plus ou moins rapidement voire consommer suffisament d'espace swap pour ralentir l'ensemble des activités du système.

    -W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  12. #12
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Citation Envoyé par damdam78 Voir le message
    Existe-il une fonction du même type que select qui renvoie un code d'erreur disant que le buffer socket en émission est plein et donc qu'une émission n'est pas possible sans rendre mon programme bloquant ?
    Oui... send... qui renvoit WSAEWOULDBLOCK si c'est plein !

    Sinon, tu peux attacher un signal au 'write' qui te diras si le buffer est plein ou non, mais dans ce cas, difficile de savoir quelle quantité de buffer est disponible.
    La gestion de paquets en local est à mon avis superflu, tu risque d'entrer dans des problêmes de gestion de mémoire bien plus "graves" à mon avis.
    Quant à passer aux sockets bloquants, c'est une solution de facilité....

  13. #13
    Membre averti
    Inscrit en
    Juin 2007
    Messages
    52
    Détails du profil
    Informations forums :
    Inscription : Juin 2007
    Messages : 52
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    select accepte le paramètre timeout qui s'il est non null mais avec timeval null doit retourner sans attendre


    Maintenant à quoi cela sert-il d'ajouter des seaux pour amortir le débordement de la pile IP: les affichages auront un retard dont la borne supérieure risque d'être difficile à définir.

    La mémoire du système n'étant pas infinie, le programme risque de planter plus ou moins rapidement voire consommer suffisament d'espace swap pour ralentir l'ensemble des activités du système.

    -W
    J'essai d'utiliser la fonction select en non bloquant, voici mon 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
    void IONet::write_to_socket()
    {
      int ret = 0;
      fd_set writefs;
      timeval l_time;
     
      FD_ZERO(&writefs);
      FD_SET(_socket, &writefs);
     
      l-time.tv_sec = 0;
      l-time.tv_usec = 0;
     
      SOCKADDR * addr = _cliAddr.asSockAddr();
      ((sockaddr_in*)addr)->sin_addr.s_addr = INADDR_BROADCAST;
      if(select(_socket+1,NULL,&writefs,NULL,&l_time)==1)
        ret = ::sendto(_socket,_ostring.base,_ostring.length,
                      0, addr, sizeof(SOCKADDR));
     
    //traitement de ret
    ...
    }
    Avec ce code, malgré que le buffer d'émission soit plein, le message est quand même envoyé. Voyez-vous où j'aurai pu commettre une erreur ?
    Par contre si j'utilise
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select(_socket+1,NULL,&writefs,NULL,NULL)
    Aucune erreur n'est provoquée, mais j'ai peur que bloquer le programme puisse produire des problèmes à d'autres endroits...

  14. #14
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 787
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 787
    Par défaut
    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
    void IONet::write_to_socket()
    {
      int ret = 0;
      fd_set writefs;
      timeval l_time;
     
      FD_ZERO(&writefs);
      FD_SET(_socket, &writefs);
     
      l-time.tv_sec = 0;  // par quelle magie le 
      l-time.tv_usec = 0; // compilo accepterait cela?
     
      SOCKADDR * addr = _cliAddr.asSockAddr();
      ((sockaddr_in*)addr)->sin_addr.s_addr = INADDR_BROADCAST;
      if(select(_socket+1,NULL,&writefs,NULL,&l_time)==1)
        ret = ::sendto(_socket,_ostring.base,_ostring.length,
                      0, addr, sizeof(SOCKADDR));
      
    //traitement de ret
    stricto sensu, select va retourner la liste des descripteurs prêts à émettre parmi ceux dans [1.._socket].
    => y compris celle qui ont un numéro de descripteur plus petit (que votre
    programme a pu ouvrir par ailleurs).

    Il serait peut être plus avisé de tester s'il y a des sockets dans l'intervalle acceptant des écritures:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     if(select(_socket+1,NULL,&writefs,NULL,&l_time) > 0)
    Et dans ce cas, s'assurer que c'est le "bon" descripteur qui est prêt:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (FD_ISSET(_socket, &writefs))
    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  15. #15
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Si je ne m'abuse, quand le select t'indique qu'une socket est dispo en écriture, ca veut dire qu'elle a un bout de buffer de dispo mais pas forcément aussi grand que tu le souhaite. Je ne suis pas sur que ton émission soit garantie si ton message est un peu gros. Je persiste à penser que tu t'acharnes à essayer de corriger quelque chose qui peut survenir du fait que t'es en UDP. La perte de message est inhérente à ce protocole.

  16. #16
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 787
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 787
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Si je ne m'abuse, quand le select t'indique qu'une socket est dispo en écriture, ca veut dire qu'elle a un bout de buffer de dispo mais pas forcément aussi grand que tu le souhaite.
    Pour info: sur les systèmes U*X, la taille de ce "bout" est donnée par SO_SNDLOWAT. C'est la capacité minimale disponible pour que le select dise que le descripteur est OK. Comme toujours la valeur par défaut dépend de l'implémentation mais est plutôt de l'ordre de quelques multiples de 1024.
    Je suppose que sous Windows, on doit avoir des équivalents.

    => L'overhead pour expédier un paquet est le même qu'il soit "petit" ou plus grand que le MTU size (dans ce cas, TCP/IP segmente...). Là aussi il y a peut être des options de design à revisiter pour optimiser un peu.

    Je persiste à penser que tu t'acharnes à essayer de corriger quelque chose qui peut survenir du fait que t'es en UDP. La perte de message est inhérente à ce protocole.
    Yup mais pas à l'application puisque
    Ce que j'ai remarqué, c'est lors de ces erreurs WSAWOULDBLOCK, certaines dérèglent mon affichage(suppression d'information, décalage...) et se remettent correctement lors de la réception d'un nouveau paquet.
    Il me semble donc vu cette constatation, que mon message est émis de manière incorrecte (le message n'est pas complet, il est corrompu...).
    C'est ce problème de saut des informations de ma carte que j'essaie de supprimer, je souhaite donc résoudre ce problème à la source: en éliminant les erreurs d'émission WSAWOULDBLOCK.
    Vu de loin, on envoie des mises à jour sous la forme d'une suite de paquets UDP. Mais côté récepteur il ne semble pas facile à déterminer si la mise à jour est complète/exploitable et peut être "affichée".

    Si on cherche à résoudre le problème à l'affichage, c'est sans doute cet aspect - est ce que le message est "complet" et çà se passe côté récepteur - qu'il faudrait travailler.

    Comme cela vous a été rappelé plusieurs fois, UDP ne garantit pas que les données "arrivent" - Si elles ne sont pas émises, vous savez pourquoi mais l'application doit gérer cela et çà se fait côté récepteur pour peu que les "messages" soient quelques peu structurés.

    Une contrainte qui n'a pas été mentionnée (et qui n'est peut être pas "forte") c'est le retard "acceptable" entre ce qui est affiché et ce dont on rend compte.

    -W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. Problème erreurs sockets sous Linux
    Par Ange44 dans le forum Linux
    Réponses: 6
    Dernier message: 05/09/2006, 16h16
  2. Erreur Socket Asynchrone 10053
    Par QAYS dans le forum Delphi
    Réponses: 2
    Dernier message: 16/06/2006, 07h44
  3. TIdHTTPServer et erreur socket # 10049
    Par DaRiaN dans le forum Composants VCL
    Réponses: 2
    Dernier message: 20/04/2006, 16h04
  4. SQL Server: Java Erreur Socket
    Par BenoitM dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 28/04/2003, 16h32

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