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 :

Winsock et multithreading en C


Sujet :

Réseau C

  1. #1
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut Winsock et multithreading en C
    J'ai posé une question liée à celle-ci sur le forum réseau, mais étant donné qu'il n'y a personne (ou du moins presque) sur ce forum, je repose ma question ici. Veuillez m'excuser par avance si vous avez déjà été faire un tour sur le forum réseau. De toute façon, mon programme est essentiellement en C.

    Y-a-t-il des précautions particulières à prendre avec les fonctions Winsock (socket, connect, send, etc...) lorsque le programme est multithread?
    Si je pose la question, c'est parce que je rencontre des problèmes avec un programme qui lance plusieurs threads en parallèle, chacun d'eux tentant d'ouvrir une connexion vers un serveur. Les connect() ont tendance à échouer avec le message d'erreur "The specified address is already in use".
    Si vous voulez davantage de détails, https://www.developpez.net/forums/showthread.php?t=284857

    Merci d'avance.

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Par défaut
    Je n'ai pas la solution mais peut être une piste. Il me semble que le systeme met du temps à liberer la ressource. En d'autres termes, meme si tu fermes la socket dans ton programme, le systeme ne va pas liberer le port tout de suite (seulement au bout de qqs seconds, voir qqs minutes).
    Je crois que le comportement est à peu pres le meme sous linux.

  3. #3
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    Je pense que ce doit être (mais peut-être l'avez-vous déjà dans votre code) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
       /*
        *On arrete toute emission et reception sur le socket
        */
       shutdown(sockno,2);
     
       /*
        * On ferme le socket
        */
       close(sockno);
    ce code n'est pas testé en multi-threading, mais marche fort bien en mono.. Par contre jamais testé sous Windows.

  4. #4
    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 souviron34
    Je pense que ce doit être (mais peut-être l'avez-vous déjà dans votre code) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
       /*
        *On arrete toute emission et reception sur le socket
        */
       shutdown(sockno,2);
     
       /*
        * On ferme le socket
        */
       close(sockno);
    ce code n'est pas testé en multi-threading, mais marche fort bien en mono.. Par contre jamais testé sous Windows.
    Extrait de http://emmanuel-delahaye.developpez....#projet_reseau
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
                         shutdown (csock, 2);
                         printf ("closing client socket %d...\n", csock);
                         closesocket (csock), csock = INVALID_SOCKET;

  5. #5
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    tiens je ne connaissais pas closesocket.....

    Quelle est la principale différence avec close, Emmanuel ?

    Et pourquoi ça passe une écriture comme ça à la compile :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          sock_err = closesocket (sock), sock = INVALID_SOCKET;
    ??

    Faut pas un ";" entre les 2 ??

  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 souviron34
    tiens je ne connaissais pas closesocket.....

    Quelle est la principale différence avec close, Emmanuel ?
    C'est une windowserie. Il n'y a pas de close() sous Windows.

    Tu n'as pas regardé le début des fichiers sources de mon article sur mon site ?

    Et pourquoi ça passe une écriture comme ça à la compile :
    Parce que c'est du C correct.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
          sock_err = closesocket (sock), sock = INVALID_SOCKET;
    ??

    Faut pas un ";" entre les 2 ??
    pas ici. c'est exprès. C'est l'opérateur , (comma operator) que tu utilises dans for()...

    Il me sert surtout à préserver l'aspect 'insécable' malgré l'indentation automatique...

  7. #7
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    On apprend à tout age...

    Cependant permet-moi de douter de l'utilité (et de la bonne disposition sur le forum) de placer un usage tel que celui-ci du comma operator...

    Je ne pense pas , si j'en crois ce que je trouve sur le Net, que ce soit à recommander (et donc à placer sur le forum comme exemple) :

    Faq C :

    http://www.c-faq.com/~scs/cclass/int/sx4db.html

    The most common (and in fact the only common) example is in a for loop
    Aussi : (manuel HPUX)

    http://docs.hp.com/en/B3901-90013/ch05s06.html

    All expressions return values. When you use a comma operator, the expression returns the value of the rightmost expression. For example, the following statement sets variable j to 2:

    j = (x = 1, y = 2);

    Assignments such as these, however, are considered poor programming style. You should confine use of the comma operator to for loops.
    et aussi K&R :

    Comma operators should be used sparingly. The most suitable uses are for constructs strongly related to each
    other, as in the for loop in reverse, and in macros where a multistep computation has to be a single
    expression.
    donc



    Par contre cela semble pas mal en usage en C++ et en Java....

  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 souviron34
    et aussi K&R :
    The most suitable uses are for constructs strongly related to each other, as in the for loop in reverse, and in macros where a multistep computation has to be a single expression.
    A rapprocher de
    Citation Envoyé par -ed-
    Il me sert surtout à préserver l'aspect 'insécable'
    Et pour la fin de la remarque du K&R :

    Extrait de http://emmanuel-delahaye.developpez....inc/sysalloc.h :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define FREE(p) (free((void *)(p)),(p)=NULL)

  9. #9
    Expert confirmé

    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    10 610
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Billets dans le blog
    2
    Par défaut
    d'accord avec toi pour les macros....

    Mais quand même je n'en ferais pas vraiment la promotion pour un truc général dans le code...

    Quand tu appuies à chaque fois sur le fait que quand on fait un free, il faut remettre le pointeur à NULL, tu n'écris pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
         free(ptr) , ptr=NULL ;
    Alors pourquoi un traitement différent ?

    Et d'autre part,

    -ed- a écrit :
    souviron34 a écrit :
    tiens je ne connaissais pas closesocket.....

    Quelle est la principale différence avec close, Emmanuel ?
    C'est une windowserie. Il n'y a pas de close() sous Windows.
    Pas de problème avec ça, mais à ce compte-là faut le préciser..

    Que la fonction et la manière unixienne est close.. Et que sous Windows c'est closesocket... (sauf si on utilise cygwin où close marche...)

  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 souviron34
    Quand tu appuies à chaque fois sur le fait que quand on fait un free, il faut remettre le pointeur à NULL, tu n'écris pas :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
         free(ptr) , ptr=NULL ;
    Ben si. Tu devrais lire mon code plus souvent... Idem avec tous les ADT (FILE etc.)

    Pas de problème avec ça, mais à ce compte-là faut le préciser..

    Que la fonction et la manière unixienne est close.. Et que sous Windows c'est closesocket... (sauf si on utilise cygwin où close marche...)
    Bah, c'est écrit dans le header (que j'ai recopié dans chaque source)
    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
     
    #if defined (WIN32)
     
    #include <winsock2.h>
     
    #elif defined (linux)
     
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <unistd.h> /* close */
     
    #define INVALID_SOCKET -1
    #define SOCKET_ERROR -1
     
    #define closesocket(s) close (s)
    typedef int SOCKET;
    typedef struct sockaddr_in SOCKADDR_IN;
    typedef struct sockaddr SOCKADDR;
     
    #else
    #error not defined for this platform
    #endif

  11. #11
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    Merci à tous pour vos réponses et désolé pour le retard de la mienne (RTT )...
    J'utilise déjà shutdown() et closesocket(). L'explication qui me semble la plus probable est celle de Sanguko (cf première réponse), mais comment en être sûr?
    Si je lance plusieurs connect() à la suite, que j'envoie les messages, et que je ferme les sockets après, alors je peux répéter ces opérations sans que le problème apparaisse. En revanche, si je lance plusieurs threads en parallèle, il arrive (trop souvent) que les connect() échouent parce qu'aucun port n'est libre. Les choses s'améliorent un peu si je place tous mes appels de fonctions Winsock dans une section critique (EnterCriticalSection() et LeaveCriticalSection()), néanmoins le programme se fige encore par moments. En outre, si je relance le programme peu de temps après qu'il a terminé, les connect() ont tendance à échouer dès le départ, ce qui me fait penser que c'est peut-être un problème de ressources système que Windows mettrait du temps à libérer???
    Quelqu'un a-t-il déjà été confronté à un tel problème?

    Encore merci pour votre aide et vos suggestions.

  12. #12
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    Comme suggéré par souviron34 (merci), j'ai changé le paramètre de shutdown() de SD_SEND en SD_BOTH, et il semblerait que cela améliore les choses (je sais, ça fait beaucoup de "semble").
    Je ne comprends vraiment pas où est le probème? En ce moment, j'effectue des tests avec 10 000 clients, 190 threads en parallèle au maximum. Parfois, le programme tourne sans problème et il y a moins de 1000 tentatives de connexion qui échouent; d'autres fois, le nombre d'échecs de connect() dépasse les 100 000.
    Si quelqu'un a déjà fait face au problème et peut confirmer ou infirmer l'hypothèse d'une lenteur de la libération des ressources par Windows, merci d'avance. Je rappelle que je peux éventuellement poster le code; cependant, étant donné que je n'ai pas la moindre idée d'où pourrait venir le problème, je devrais poster TOUT le code qui est relativement long.

  13. #13
    Membre éprouvé
    Avatar de granquet
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2005
    Messages
    1 201
    Détails du profil
    Informations personnelles :
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2005
    Messages : 1 201
    Par défaut
    j'ai ete confronté a un probleme similaire. impossibilitée de faire tourner un programme avec une boucle du type:
    > thread_create -> connect -> action -> closesocket -> shutdown -> thread_exit <

    je ne me souviens plus des symptomes exacts (le programme realisait des connexions SSH//HTTP//Ping//dhcp//dns etc ... :: stress testing de mon server maison).
    au bout d'un nombre (faible) de connect(),close(),shutdown(); le programme cessait d'etre operationnel (:: plus rien sur le reseau) alors que les fonctions retournaient des valeurs correctes.

    j'ai fini par maudire windows et je suis retourné sous linux, la solution au probleme m'interresserais ... c'est deplaisant cette "zone d'ombre"

  14. #14
    Membre émérite Avatar de stephl
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2007
    Messages
    643
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2007
    Messages : 643
    Par défaut
    OK, je vous préviendrai si j'arrive à résoudre le problème.
    Pour le moment, les choses se sont tout de même améliorées depuis que j'ai enfermé tous les appels aux fonctions Winsock dans des sections critiques. Au bout d'un certain nombre d'itérations cependant, il arrive encore que le programme ralentisse, mais il ne se fige plus aussi longtemps qu'avant.
    En revanche, dans le problème auquel je suis confronté, connect() ne retourne pas normalement: la valeur de retour est SOCKET_ERROR et le message retourné par WSAGetLastError() est "The specified address is already in use".

Discussions similaires

  1. winsock + multithreading
    Par chonos dans le forum Développement
    Réponses: 5
    Dernier message: 11/09/2006, 12h03
  2. [Winsock] Envoi et recupération d'une image
    Par arnolanf dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 29/11/2002, 08h49
  3. Multithreading sous HP Ux 11
    Par pykoon dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 18/10/2002, 23h36
  4. [VB6] [Winsock] Trouver un port libre
    Par Yann dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 14/10/2002, 11h23
  5. [Kylix] equivalent winsock avec kylix
    Par Victor dans le forum EDI
    Réponses: 2
    Dernier message: 08/05/2002, 07h43

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