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 :

Serveur multithread


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre du Club
    Inscrit en
    Avril 2007
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 8
    Par défaut Serveur multithread
    salut à tous et à toutes,

    j'ai crée un petit serveur en C qui gère plusieurs client à l'aide de fork et ca marche très bien, ensuite j'ai voulue passer au threads. j'ai essyer mais ca ne marche pas.

    serveur avec fork:
    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
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    #include <sys/types.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <string.h>
    #include <stdlib.h>
     
     
    #define PORT 80  
    #define BACKLOG 5
    #define MAXDATASIZE 2048 
     
     
    char buff[MAXDATASIZE]; 
    int i;
    int sockfd, newsockfd;
    int pid, sin_size, nbytes;
    struct sockaddr_in serveraddr;   /* l'adreese de la socket serveur */
    struct sockaddr_in clientaddr;   /* l'adresse de la socket client */
    struct hostent *hostinfo;
     
    char *a;
    int count;
    pthread_t id;
     
     
    int main()
    {
    int init_socket()
     {
                    /*******CREATION DE SOCKET*******/
       if ((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1) 
         {
           printf("création de socket impossible\n");  
           exit(1);
         }
         printf("socket créé\n");
     
                   /*******REMPLISSAGE DE LA SOCKET******/
     
       serveraddr.sin_family = AF_INET;
       serveraddr.sin_port = htons(PORT);
       serveraddr.sin_addr.s_addr = INADDR_ANY;  /* remplissage automatique */
     
                /********ATTACHEMANT DE LA SOCKET AU N°PORT********/
     
       if (bind(sockfd, (struct sockaddr*) &serveraddr,\
                          sizeof(struct sockaddr_in)) == 1)
         {
           exit(1);
         }
          printf("socket connecté au réseau\n");
     
                      /*******ECOUTE SUR LE RESEAU********/
         if (listen(sockfd, BACKLOG) == -1) 
           {
            exit(1);
           }
     }     
     
     
    int connexion()
    {
         /* attente permanente */
     
         while(1) {
                    sin_size = sizeof(struct sockaddr);
     
                    if ((newsockfd=accept(sockfd,\
                          (struct sockaddr*) &clientaddr, &sin_size)) == -1)
                      {
                        exit(1);
                      }
                       printf ("client connecté\n");
                               /*************/
     
                     clientaddr.sin_family = AF_INET;
                     clientaddr.sin_port = 80;
                     memcpy((struct sockaddr*) &clientaddr.sin_addr.s_addr, hostinfo->h_addr, 4);
                     a = inet_ntoa(clientaddr.sin_addr);
     
                     printf(" adresse du client est: %s\n",a);
     
                       /********DUPLICATION DU PROCESSUS*******/
     
                     switch(pid=fork())
                       {
                            /** erreur de fork() **/
                          case(-1): close(sockfd);
                                    close(newsockfd);
                                    break;
     
                            /** libération de la socket d'écoute **/
                          case(0): close(sockfd);
                              {
                                 fprintf(stdout, "requête n°:PID=%ld\n", (long) getpid());    
                                 if (nbytes=recv(newsockfd, buff, MAXDATASIZE,\
                                                                     0) == -1)  
                                   {
                                     exit(1);
                                   }
                                   printf("la ressource est: %s\n",&buff);
     
                                   extraction();
     
                                   if ((send(newsockfd, buff, MAXDATASIZE, 0)) == -1) 
    	                         {
                                       printf("echec\n");
                                       exit(1);
                                     }
                               }
                        }
    	}
    }
    pouvez vous me dire comment remplcer la partie de fork avec un les threads.

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    D'abord, qu'est ce qui n'a pas marché avec la version "thread" ? Poste nous ton code.

    Il y a une différence essentielle entre "fork" et "thread"
    • avec un fork, il y a duplication de l'espace mémoire du père et création d'un nouveau processus fils. Les ancienne variables du père sont recopiées intégralement (à l'exception de quelques unes) et appartiennent maintenant exclusivement au fils. Elles vivent leur vie de manière indépendante (une modification d'une variable dans le fils n'aura aucun impact sur la même variable dans le père)
    • avec un thread, il y a création d'un nouveau thread (quelle lapalissade !) mais le process créateur et le thread nouvellement créé partagent le même espace mémoire. Donc si le thread nouvellement créé modifie une variable, le thread créateur peut être impacté. C'est pour cela qu'il devient important d'utiliser les moyens permettant des communications inter thread (section critique, variable atomiques, ...).

    Donc dans ton cas, cela passe probablement par la création d'un tableau de socket fils et chaque thread créé doit gérer un et un seul des socket de ce tableau. Il y a un accès concurrent à ce tableau (quand thread créateur ajoute un noveau socket dans le tableau et que un thread nouvellement créé supprime un des socket suite à sa fermeture par exemple)
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Membre du Club
    Inscrit en
    Avril 2007
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 8
    Par défaut
    D'abord, qu'est ce qui n'a pas marché avec la version "thread" ? Poste nous ton code.
    je me suis mal exprimé.

    les threads marche bien. j'ai fait une boucle de 5 threads, alors après la 6ième tentative le serveur ne traite plus de requete (c'est logique).

    je veut qu'a la 7ième requete le serveur la traite en appelant un des thread déja crèè, sachant qu'a la fin, je ne tue pas le thread.

    comment je peut le faire?
    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
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
     
     #include <sys/types.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <stdio.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <string.h>
    #include <stdlib.h>
     
     
    #define PORT 80  
    #define BACKLOG 5
    #define MAXDATASIZE 2048 
     
     
    char buff[MAXDATASIZE]; 
    int i;
    int sockfd, newsockfd;
    int pid, sin_size, nbytes;
    struct sockaddr_in serveraddr;   /* l'adreese de la socket serveur */
    struct sockaddr_in clientaddr;   /* l'adresse de la socket client */
    struct hostent *hostinfo;
     
    char *a;
    int count;
    x = 0, nthreads = 0;
    pthread_t id[NB_THREADS];
     
     
     
    int main()
    {
    int init_socket()
     {
                    /*******CREATION DE SOCKET*******/
       if ((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == -1) 
         {
           printf("création de socket impossible\n");  
           exit(1);
         }
         printf("socket créé\n");
     
                   /*******REMPLISSAGE DE LA SOCKET******/
     
       serveraddr.sin_family = AF_INET;
       serveraddr.sin_port = htons(PORT);
       serveraddr.sin_addr.s_addr = INADDR_ANY;  /* remplissage automatique */
     
                /********ATTACHEMANT DE LA SOCKET AU N°PORT********/
     
       if (bind(sockfd, (struct sockaddr*) &serveraddr,\
                          sizeof(struct sockaddr_in)) == 1)
         {
           exit(1);
         }
          printf("socket connecté au réseau\n");
     
                      /*******ECOUTE SUR LE RESEAU********/
         if (listen(sockfd, BACKLOG) == -1) 
           {
            exit(1);
           }
     }     
     
     
    int connexion()
    {
         /* attente permanente */
     
         while(1) {
                    sin_size = sizeof(struct sockaddr);
     
                    if ((newsockfd=accept(sockfd,\
                          (struct sockaddr*) &clientaddr, &sin_size)) == -1)
                      {
                        exit(1);
                      }
                       printf ("client connecté\n");
                               /*************/
     
                     clientaddr.sin_family = AF_INET;
                     clientaddr.sin_port = 80;
                     memcpy((struct sockaddr*) &clientaddr.sin_addr.s_addr, hostinfo->h_addr, 4);
                     a = inet_ntoa(clientaddr.sin_addr);
     
                     printf(" adresse du client est: %s\n",a);
     
                       /********CREATION DES THREADS*******/
     
         if (pthread_create(&id[x++], NULL, (void*)traitement, NULL) != 0)
            {
                printf("création du thread impossible\n");
     
             }
    	 else
    	   {
    	     if (nthreads++ >= NB_THREADS)
    	      break;
    	   } 
           }
          for (x = 0; x < nthreads; x++)
             {
    	   if (pthread_join(id[x], NULL) < 0)
    	     {
    	      printf("erreur de join\n");
                 }
    	     close(newsockfd);
    	     close(sockfd);
    	     return 0;                    
    	}
    }

  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 nesrine_k Voir le message
    je me suis mal exprimé.

    les threads marche bien. j'ai fait une boucle de 5 threads, alors après la 6ième tentative le serveur ne traite plus de requete (c'est logique).

    je veut qu'a la 7ième requete le serveur la traite en appelant un des thread déja crèè, sachant qu'a la fin, je ne tue pas le thread.

    comment je peut le faire?
    Ce code est incomplet (ne compile pas). Il faut donner le code de 'traitement()'.

    J'ai remis un peu d'ordre dans le code du serveur... La gestion des clients m'a l'air calamiteuse...

    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
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
     
     
    /* -ed- compatibilité Windows, organisation, mise en forme */
    /* server.c */
     
    #ifdef __cplusplus
    #error Be sure you are using a C compiler...
    #endif
     
    #if defined (WIN32)
     
    #include <winsock2.h>
     
    #elif defined (linux) || defined (_POSIX_VERSION) || defined (_POSIX2_C_VERSION)\
     || defined (_XOPEN_VERSION)
     
    #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
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
     
    /* macros ============================================================== */
     
    #define PORT 80
    #define BACKLOG 5
    #define MAXDATASIZE 2048
    #define NB_THREADS 5
     
    /* constants =========================================================== */
    /* types =============================================================== */
    /* structures ========================================================== */
    /* private data ======================================================== */
    /* private functions =================================================== */
     
    char buff[MAXDATASIZE];
    int i;
    int sockfd, newsockfd;
    int pid, sin_size, nbytes;
    struct sockaddr_in serveraddr;  /* l'adreese de la socket serveur */
    struct sockaddr_in clientaddr;  /* l'adresse de la socket client */
    struct hostent *hostinfo;
     
    char *a;
    int count;
    int x = 0, nthreads = 0;
    pthread_t id[NB_THREADS];
     
     
    static void *traitement(void*p_data)
    {
       (void)p_data;
       return NULL;
    }
     
    void init_socket (void)
    {
       /*******CREATION DE SOCKET*******/
       if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
       {
          printf ("création de socket impossible\n");
          exit (1);
       }
       printf ("socket créé\n");
     
       /*******REMPLISSAGE DE LA SOCKET******/
       serveraddr.sin_family = AF_INET;
       serveraddr.sin_port = htons (PORT);
       serveraddr.sin_addr.s_addr = INADDR_ANY; /* remplissage automatique */
     
       /********ATTACHEMANT DE LA SOCKET AU N°PORT********/
       if (bind (sockfd, (struct sockaddr *) &serveraddr,
                 sizeof (struct sockaddr_in)) == 1)
       {
          exit (EXIT_FAILURE);
       }
       printf ("socket connecté au réseau\n");
     
       /*******ECOUTE SUR LE RESEAU********/
       if (listen (sockfd, BACKLOG) == -1)
       {
          exit (EXIT_FAILURE);
       }
    }
     
    int connexion (void)
    {
       /* attente permanente */
       while (1)
       {
          sin_size = sizeof (struct sockaddr);
     
          if ((newsockfd = accept (sockfd,
                                   (struct sockaddr *) &clientaddr,
                                   &sin_size)) == -1)
          {
             exit (EXIT_FAILURE);
          }
          printf ("client connecté\n");
     
          /*************/
          clientaddr.sin_family = AF_INET;
          clientaddr.sin_port = 80;
          memcpy ((struct sockaddr *) &clientaddr.sin_addr.s_addr,
                  hostinfo->h_addr, 4);
          a = inet_ntoa (clientaddr.sin_addr);
     
          printf (" adresse du client est: %s\n", a);
     
          /********CREATION DES THREADS*******/
          if (pthread_create (&id[x++], NULL, traitement, NULL) != 0)
          {
             printf ("création du thread impossible\n");
          }
          else
          {
             if (nthreads++ >= NB_THREADS)
                break;
          }
       }
     
       for (x = 0; x < nthreads; x++)
       {
          if (pthread_join (id[x], NULL) < 0)
          {
             printf ("erreur de join\n");
          }
          closesocket (newsockfd);
       }
       closesocket (sockfd);
     
       return 0;
    }
     
    static int server (void)
    {
     init_socket ();
     connexion ();
     return 0;
    }
     
    /* entry point ========================================================= */
     
    /* ---------------------------------------------------------------------
       --------------------------------------------------------------------- */
    int main (void)
    {
       int ret;
     
    #if defined (WIN32)
       WSADATA wsa_data;
       int err = WSAStartup (MAKEWORD (2, 2), &wsa_data);
     
       if (!err)
       {
          puts ("WIN: winsock2: OK");
    #else
       int err;
    #endif
     
       server ();
     
    #if defined (WIN32)
       WSACleanup ();
    }
    #endif
     
    if (err)
    {
       ret = EXIT_FAILURE;
    }
    else
    {
       ret = EXIT_SUCCESS;
    }
     
    return ret;
    }
    Toutes ces globales sont horribles, et obscurcissent le code inutilement (qui fait quoi ?).

  5. #5
    Membre du Club
    Inscrit en
    Avril 2007
    Messages
    8
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 8
    Par défaut
    Envoyé par Emmanuel DelahayeCe
    code est incomplet (ne compile pas). Il faut donner le code de 'traitement()'.
    vous pouvez mette pour la fonction traitement ce que vous vous voulez, par exemple compter le nombre de connexion d'un client vers le serveur.

    ma fonction traitement est confidencielle.je ne peut l'exposé.

    mes threads fonctionne très bien, je veut seulement l'ai réutilisés.

    comment faire?

  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 nesrine_k Voir le message
    mes threads fonctionne très bien, je veut seulement l'ai réutilisés.

    comment faire?
    http://emmanuel-delahaye.developpez.com/reseaux.htm

    Il y a un exemple d'ébauche de serveur multi-clients avec les threads.

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 747
    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 747
    Par défaut je ferais comme çà
    Pour cela, il faut qu'après avoir terminé son travail la thread aille voir s'il y a encore du boulot.

    Ce qui suggère un modèle de type "work queue":
    - des threads déposent des indications du travail à faire,
    - d'autres les retirent et 'font' le boulot

    Dans le cas général, la "work queue" peut être une liste sur laquelles les opérations devront être synchronisés(ex: mutex) ou atomiques(instruction machine).

    Mais avec le couple listen/accept, nous avons une "work queue" implicite qui peut être utilisée: listen prend en paramètre le nombre de sessions traitables simutanément et accept retourne la première connexion en attente.

    Ce qui dans le cas du code proposé pourrait se traduire par créer les threads (au niveau de main) pour qu'elles exécutent l'appel à accept, traitent la requête client et attende le client suivant sur 'accept'.

    Comme il s'agit d'un serveur et qu'on a peut être envie qu'il se termine proprement, il sera peut être astucieux de rendre l'accept 'non bloquant' et introduire un test de sortie:

    1 - j'ai terminé?
    2 - nouvelle connexion?
    3 - j'attends n millisecondes,
    4 - je recommence en 1.

    Bon courage

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

Discussions similaires

  1. Arrêt d'un serveur multithread
    Par bambou dans le forum Entrée/Sortie
    Réponses: 7
    Dernier message: 07/07/2010, 16h04
  2. conception serveur multithread
    Par nivose110 dans le forum Réseau
    Réponses: 12
    Dernier message: 17/07/2006, 16h43
  3. Question Serveur Multithread
    Par Mr_Chut dans le forum Réseau
    Réponses: 10
    Dernier message: 09/06/2006, 17h27
  4. Réponses: 5
    Dernier message: 11/01/2006, 07h58

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