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

C++ Discussion :

Problème Seveur multi-thread


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 36
    Par défaut Problème Serveur multi-thread
    Bonjour,

    J'ai reçu un devoir dont vous pouvez avoir l'énnoncé ici.
    Tout d'abord, pour créer un serveur pouvant gérer plusieurs clients je me suis dirigé vers l'idée d'un serveur multi-thread, j'ai vu qu'il y avait aussi une solution consistant à utiliser des sockets asynchrones mais j'ai pas trouvé beaucoup d'info là dessus et ça me semble assez compliqué.
    Donc après avoir décider de faire un serveur multithread, j'ai donc fait des recherche là dessus et j'ai trouvé cet exemple donné dans vos tutaux, je comprend à peu près tout mais j'aurais tout de même besoin d'éclaircissements:

    Tout d'abord les fonctions utilisés là ont-elles le même nom sous linux? Car pour que le programme soit éxécutable sous windows et linux je compte faire un en tête du style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #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>
    (Pour le moment j'ai mis ces bibliothèques pour linux car il semblerait que ce soit les "classiques" pour l'utilisation de sockets)

    Ensuite le passage du code que je n'ai pas bien compris est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    static DWORD WINAPI ThreadLauncher(void *p){
    			struct thread_param *Obj = reinterpret_cast<struct thread_param*>(p);               
    			serveur *s = Obj->ser;                          
    			return s->ClientThread(Obj->soc);       
    		}
    En réalité au final je ne comprend pas bien quelles information contient le socket utilisé par la fonction "ClientThread", je suppose que c'est le socket correspondand au client mais ensuite je ne comprend pas bien comment faire que chaque thread gère son client, et surtout comment le serveur fait pour envoyer un message à tout les clients. Donc un peu d'aide ne serait pas de trop (je trouve que pour notre niveau le prof nous demande vraiment un truc très difficile, surtout qu'on a qu'un mois pour faire ça ).
    Merci d'avances pour vos résponses, explications ou conseils.

  2. #2
    Membre confirmé
    Inscrit en
    Octobre 2006
    Messages
    114
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 114
    Par défaut probleme serveur multi-thread
    slt,
    moi aussi j'avais le mm probleme que toi le mois dernier. Mais j'ai finalement pu creer ma propre classe Thread ou j'encapsule toutes ses fonctions.
    Le 1er conseil que je te donnerai c'est te lire cet article : http://www.devarticles.com/c/a/Cplus...hreading-in-C/
    il est en Anglais mais vraiment bien. Il te donne le concept du multithreading en C++. Ensuite utilise la classe Thread que j'ai uploader avec ce mail.
    L'idee est de comprendre la fonction accept est bloquante DONC tu NE dois PAS la mettre dans le main. C'est la raison pour laquelle elle doit etre placee dans un thread.
    Pour utiliser la classe que je t'ai passe c'est simple. Par ex suppose que ton network classe s'appelle network.
    Tu fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class network : public Thread 
     { //Tu dois imperative definir la fonction run ();
       int run()
        {
         //Le code principal de ta fonction
        //N'oublie pas de mettre une boucle infinie
       return 0; //normalement tu ne dois jamais arriver a cet etape 
     
      }
     
     
     }
    Cote serveur, tout ce que tu as a faire c'est de garder TOUS les sockets retournes par la fonction ACCEPT quelque part et assigner ces sockets a des clients. Apres avoir recu un nouveau socket de la fonction ACCEPT, TU dois appeller LISTEN encore et puis ACCEPT. Le code ressemble a :
    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
     
    for (;;) //boucle infinie
    	{
    	int sinsize = sizeof(csin);
    	if((_acceptingsocket = accept(_listeningsocket, (SOCKADDR *)&csin, &sinsize)) != INVALID_SOCKET)
    	{	_numberOfConnectedClients++;
    		//TODO: before putting the brand-new socket into the shared memory area, first ask the incoming client 
    		//to identify itself by receiving a message from him
    		// EX: recv : are you a player or a spectator?
    		 cout <<"Well done ..."<<endl;
    		 cout <<"You are connected to IP : ..."<< /*ntohl (csin.sin_addr.S_un.S_addr)*/ inet_ntoa(csin.sin_addr) <<endl;
    		 //cout <<"On port number..."<<ntohs(csin.sin_port)<<endl;
    		 cout <<"There are "<<_numberOfConnectedClients<<"Connected Clients... "<<endl;
    		 this->_shared.SetSocket(_acceptingsocket);
    	}
     
    	if (listen(_listeningsocket, 5) == SOCKET_ERROR) cerr<<"Fail to listen"<<endl;
    	else cout <<"Listening to connections ... "<<endl;
    	}
    Un autre point IMPORTANT, puisque tu geres plusieurs clients a la fois, TU dois penser au probleme de synchronisation, car 2 clients ne peuvent pas avoir le meme socket. Donc je te renvoie sur cet excellent article de GAMASUTRA : http://www.gamasutra.com/features/20...paquet_pfv.htm
    Voila je crois t'avoir aide autant que possible, n'hesite pas de me poser des questions supplementaires, email : franclin@netcourrier.com (le moyen le plus sur et le plus rapide de m'avoir.)
    @+
    Fichiers attachés Fichiers attachés

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 36
    Par défaut
    Merci bien pour tous ces conseil je vais de ce pas lire tes articles

  4. #4
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Par défaut
    Je pense que tu sais que dès que l'on fait intervenir des threads, ça devient très difficile à gérer (notamment les données partagées).

    Il est parfaitement possible de gérer plusieurs clients avec un seul processus/thread en utilisant select. Pourquoi ne pas utiliser cela ? Et utiliser des threads pour des opérations couteuses (le transfert d'un fichier où je ne sais quoi).

    Le code peut alors ressembler simplement à cela (c'est un code C) :

    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
    while(1)
      {
        maxfd = fdConnection+1;
        if(maxfd< STDIN_FILENO+1)
          maxfd = STDIN_FILENO+1;
     
        FD_ZERO(&setfd);
        FD_SET(fdConnection, &setfd);
        FD_SET(STDIN_FILENO, &setfd);
     
        /** repositionnement pour chaque client */
     
        clientListBegin();
        for(i = 0; i<clientListGetSize(); i++)
        {
          int lsocket = clientListGetSocket(i);
          FD_SET(lsocket, &setfd);
          if(lsocket+1>maxfd)
            maxfd = lsocket+1;
        }
        clientListEnd();
     
        if(select(maxfd, &setfd, 0,0,0) == -1)
        {
          perror("select");
          exit(EXIT_FAILURE);
        }
     
        if(FD_ISSET(STDIN_FILENO, &setfd))
        {
          fprintf(stderr, "Close program : \n");
          break;
        }
        /*on matte ce que les gens racontent*/
        clientListBegin();
        for(i = 0; i<clientListGetSize(); i++)
        {
          lsocket = clientListGetSocket(i);
          if(FD_ISSET(lsocket, &setfd))
          {
            //tailleget = read(lsocket, buffer, sizeof(buffer)-1);
            tailleget =  recv(lsocket, buffer, sizeof(buffer)-1, MSG_PEEK);
            if(tailleget == -1)
            {
              perror("recv");
              continue;
            }
     
            if(tailleget == 0)
            {
              fprintf(stderr, "Disconnection\n");
              close(lsocket);
              clientListPrepareToRemove(i);
              continue;
            }
     
            char *  realEnd;
     
            realEnd = memchr(buffer, '\n', tailleget);
            if(realEnd == NULL)
            {
              fprintf(stderr, "Server receive a too long packet\n");
              continue;
            }
     
            tailleget = realEnd - buffer + 1;
     
            tailleget = recv(lsocket, buffer, tailleget,0 );
     
     
            if(tailleget == -1)
            { /*n'arrivera jamais ici*/
              perror("recv");
            }
            else
            {
              /*fin de connexion ?*/  /*n'arrivera jamais ici*/
              if(tailleget == 0)
              {
                fprintf(stderr, "Disconnection...\n");
                close(lsocket);
                clientListPrepareToRemove(i);
              }
              else
              {
                buffer[tailleget] = '\0';
                printf(" * PACKET :  : %s\n", buffer);
                serverInterpreter(buffer, lsocket);
                DEBUG("End serverInterpreter");
              }
            }
          }
        }
        clientListEnd();
     
        DEBUG("debut demande de connexion");
     
     
        /* nouvelle demande de connexion ?*/
        if(FD_ISSET(fdConnection, &setfd))
        {
          fprintf(stderr, "Demande de connexion....\n");
          tailleaddr = sizeof addrClient;
          clientSocket = accept(fdConnection, (struct sockaddr*) &addrClient,
                                &tailleaddr);
          if(clientSocket == -1)
          {
            perror("accept");
            continue;
          }
          //fprintf(stderr, " * Port : %d", ntohs(addrClient.sin_port));
     
          if(clientListAdd(clientSocket, addrClient.sin_addr.s_addr, addrClient.sin_port) == -1)
          {
            fprintf(stderr, "Ajout client impossible\n");
          }
        }
     
        DEBUG("fin demande de connexion");
     
      }


    //N'oublie pas de mettre une boucle infinie
    return 0; //normalement tu ne dois jamais arriver a cet etape
    Ton implémentation de ta classe thread m'a l'air très mauvaise si tu ne dois faire une boucle infinie comme ça. En plus, une boucle infinie, c'est une attente active ce qu'il faut ne surtout pas faire !

    L'idee est de comprendre la fonction accept est bloquante DONC tu NE dois PAS la mettre dans le main. C'est la raison pour laquelle elle doit etre placee dans un thread.
    Cet argument n'est absolument pas valabe ! Il suffit d'utiliser select. Ta manière de raisonner suppose que ça peut bloquer dans un thread, donc que le thread dorme, mais qu'il soit toujours là ! C'est une très mauvaise solution. Ton serveur doit être capable de vivre pendant des journées, si tu as des threads qui dorment partout, ou des threads qui sont en attente actives, ça ne va pas le faire.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 36
    Par défaut
    Le programme doit être compatible windows et linux, vos fonctions le sont-elles? Sinon encore merci pour les réponses. Sinon une question plus basique... Comment on fait pour linker la bibliothèques winsock sur DevC++ ?

  6. #6
    Membre Expert
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Par défaut
    Bonjour,

    Je peux te répondre deux choses:
    • Pour la compatibilité avec linux windows et autres, utilise SDL_net et SDL_thread dont les fonctions marchent partout.
    • Dev-C++ n'est plus mis à jour par sa communauté, donc vaut mieux utiliser CodeBlocks (sinon je connais pas la réponse précise à ta question)


    Je ne sais rien de plus,

    Salut.

  7. #7
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Par défaut
    SDL_net te permettra en effet d'avoir un programme multiplate forme (linux, windows, macos). La bibliothèque pthread permet également de faire de la programmation multithread de manière portable.

    Si tu ne souhaites pas utiliser une bibliothèque supplémentaire, tu peux jetter un oeil au cours suivant :
    http://emmanuel-delahaye.developpez.com/reseaux.htm

    Il met en place un petit système de macro pour pouvoir compiler sous linux ou windows.

    Tu verras d'ailleurs un bon exemple de serveur monothread de la même manière que j'avais expliqué précédemment, en utilisant select (qui fonctionne bien sur les SOCKET sous windows, sur les socket et les file descriptor en général sous Unix/Linux).

    En effet, fd_set est défini avec mingw par :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    typedef struct fd_set {
    	u_int   fd_count;
    	SOCKET  fd_array[FD_SETSIZE];
    } fd_set;
    EDIT : Comme c'est un exercice que tu as, je m'attend à ce que tu ais à utiliser des bibliothèque bas niveau. Mais tu ne nous as pas spécifié les contraintes sur les bibliothèques utilisées, donc je ne peux pas en dire plus

  8. #8
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Salut,

    Je conseillerais plutôt boost.asio, c'est quand même ce qui se fait de plus simple et de plus portable pour le réseau en C++ en ce moment.
    De plus c'est vraiment simple et élégant d'utilisation je trouve

    Cela dit peut-être que c'est un peu trop simplifier le devoir qui requiert de se farcir du code réseau bas niveau ?
    (le lien a l'air foireux, j'ai pas réussi à trouver l'énoncé...)

    MAT.

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 36
    Par défaut
    Ah oui excusez moi pour l'énnoncé j'avait pas vu que l'adresse ne changé pas entre la page d'acceuil et celle ou il y a l'énnoncé.
    Sinon merci pour vos propositions mais je crois que je vais rester dans ce que je comprend, comme je n'ai pas beaucoup de temps, je vais essayer std et si je ne comprend pas je me débrouillerai d'abord pour que le programme marche sous windows, et ensuite je verrais pour linux.
    « A1, systèmes »
    Mise en place d'une plateforme de messagerie instantanée

    Le principe de cette plate-forme (le serveur) est de donner un espace de
    discussion à un ensemble d'utilisateurs de machines connectées par le
    réseaux (les clients). On doit donc pouvoir transmettre du texte d'un client au
    serveur et que ce texte soit mis à disposition des autres membres de la
    discussion.
    Pour vous aider dans la construction de ce projet, il est découpé en trois
    parties, de la plus simple à la plus compliquée. Le développement des trois
    parties sera évalué pour la notation du projet.

    PARTIE 1 : UNE SEULE DISCUSSION (4)
    L'objectif de cette partie est de faire dialoguer plusieurs clients en même
    temps sur un même serveur. Le fonctionnement de cette partie est très proche
    du TP « programmation pour les réseaux » de R. Raffin. Tous les clients voient
    la discussion et peuvent y intervenir.
    Fonctionnement :
    ● exécuter le serveur sur une machine (le serveur est destiné à rester en
    fonctionnement en permanence) ;
    ● chaque client se connecte au serveur grâce à l'adresse IP de ce dernier ;
    ● à chaque message d'un client vers le serveur, celui-ci renvoie le message
    vers tous les clients.
    Consignes :
    ● chaque message envoyé aux membres comporte un en-tête avec la date
    et l'heure de la réception du message par le serveur et l'expéditeur de
    ce message ;
    ● lorsqu'un client intègre ou quitte la discussion, les autres membres sont
    avertis ;
    ● le serveur continue de fonctionner indéfiniment, même sans client ;
    ● lorsque le serveur est arrêté, il prend le temps de prévenir d'abord tous
    les membres de la discussion.

    PARTIE 2 : EXTENSION PLUSIEURS DISCUSSIONS (8)
    Le serveur propose la mise en place de salles de discussions dans lesquelles
    un ensemble de membres peuvent discuter. Les discussions dans ces salles
    sont évidemment restreintes aux membres de la discussion mais un membre
    peut faire partie de plusieurs discussions.
    Fonctionnement :
    ● exécuter le serveur sur une machine ;
    ● chaque client se connecte à ce serveur grâce à son adresse IP ;
    ● une fois connecté, le serveur envoie au client la liste des discussions
    avec leurs membres. Le client choisit d'en intégrer une (ou plusieurs) ;
    ● à chaque message d'un client vers le serveur pour une discussion
    donnée, le serveur renvoie le message vers tous les clients de cette
    discussion ;
    ● si le client veut créer une discussion, une fois connecté, il en fait la
    demande au serveur. Celui-ci donnera un identifiant à la discussion, fera
    du client demandeur un membre d'office et diffusera à tous la création
    de cette discussion.
    Consignes :
    ● à vous de voir quelle est la meilleur méthode pour pouvoir participer à
    plusieurs discussions simultanées (un ou plusieurs serveurs issus de
    threads, une console pour chaque discussion ou une console commune
    avec la demande à chaque message pour connaître la discussion
    réceptrice, ...) ;
    ● chaque message envoyé aux membres comporte un en-tête avec la date
    et l'heure de la réception du message par le serveur, un identifiant de
    discussion, l'expéditeur de ce message ;
    ● lorsqu'un client intègre ou quitte une discussion, les autres membres
    sont avertis ;
    ● si tous les membres d'une discussion la quittent, elle est supprimée du
    serveur ;
    ● le serveur continue de fonctionner, même sans client ;
    ● lorsque le serveur est arrêté, il prévient d'abord tous les membres de
    toutes les discussions ;
    ● une commande permet d'obtenir une liste des membres actuels de la
    discussion à laquelle le client est connecté.

    PARTIE 3 : GESTION DES DISCUSSIONS (6)
    À la suite de la partie 2, ajouter des modérateurs qui peuvent admettre ou
    refuser un membre, éjecter un membre d'une ou plusieurs discussions et un
    super-modérateur qui peut admettre ou refuser la création d'une discussion.
    D'autre part, un client peut envoyer un message à un autre directement s'il
    connaît son identifiant, seul le super-modérateur verra passer ce message.
    Fonctionnement :
    ● identique au précédent
    ● tous les messages sont stockés sur disque dur (log), un fichier par
    discussion. On doit retrouver pour chaque discussion :
    ○ une en-tête avec le créateur de la discussion, la date et l'heure,
    ○ pour chaque message, l'expéditeur la date et l'heure,
    ○ pour chaque événement, le type, les informations, la date et l'heure
    (ajout ou suppression d'un membre, message du serveur, envoi d'un
    message, ...).
    ● les messages hors discussion sont stockés dans un fichier à part.
    Consignes :
    ● lorsque le serveur est exécuté, il ajoute forcement son propriétaire
    comme super-modérateur et comme modérateur de chaque discussion ;
    ● lorsqu'un client crée une discussion, il en devient modérateur ;
    ● pour chaque action sur la discussion, le modérateur peut ou non
    intervenir (ajout d'un membre, fermeture de la discussion) ;
    ● lorsqu'un modérateur quitte une discussion, le super-modérateur
    nomme un autre membre de la discussion. En attendant cette
    nomination, si nécessaire, la discussion est bloquée (le signaler alors
    aux membres) ;
    ● le super-modérateur existe tant que le serveur existe.

    CONSIGNES GÉNÉRALES
    ● utiliser des structures de données pour stocker les différentes données
    des applications (classe, listes, tableaux, variables) ;
    ● mettre en place un serveur sur pluton (147.94.176.19) ou lotus
    (192.168.106.6, mais accessible seulement depuis l'intérieur de l'IUT) ;
    ● le serveur accepte au maximum 10 connexions ;
    ● commenter le code pour chaque classe et fonction ;
    ● utiliser des classes, l'héritage (quand cela s'y prête), la STL, etc.
    ● penser à désalouer tout ce qui a été aloué quand cela est nécessaire.

    SUGGESTIONS D'AJOUTS POSSIBLES
    ● envoi de données autre que texte (image bitmap, objet sérialisé) et
    sauvegarde dans un répertoire local des clients ;
    ● suivi de la discussion sur un navigateur Web, sortie en HTML du texte
    échangé ;
    ● pages HTML de récapitulatif ;
    ● commentaires en Doxygen (www.doxygen.org) ;
    ● interface graphique (attention, c'est long et relativement difficile !) ;
    ● gestion de l'authentification auprès du serveur avec mot de passe crypté
    (fonction crypt()).
    AVERTISSEMENT IMPORTANT
    Vous devez impérativement vous assurer à la fin de chacune de vos séances de
    travail sur pluton (ou lotus) que vous n'avez laissé aucun processus zombie, ni
    aucun processus encore actif lié à cet exercice.
    En effet, si vous laissez un processus faire des threads à qui mieux mieux,
    vous allez (gravement) affecter les performances du serveur principal de l'IUT,
    ce qui n'est pas tolérable, et sera pris en compte dans la notation.

  10. #10
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    Si tu veux utiliser des threads portables : http://miles.developpez.com/tutoriels/cpp/boost/thread/

  11. #11
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Par défaut
    Citation Envoyé par Miles
    Si tu veux utiliser des threads portables : http://miles.developpez.com/tutoriels/cpp/boost/thread/
    C'est pas toi qui avait dit qu'il manquait beaucoup de chose dans cette bibliothèque ? De plus, j'aurais preferé qu'ils choisissent une stratégie à la Java (je parle de boost, pas du posteur), là, ça reste avec un handler, ce n'est pas ce qu'il y a de plus marrant

    Pour ma bibliothèque d'images, j'avais fait une stratégie comme dans java, avec notify, join, notifyAll, run et start, wait avec également une possibilité de les mettre dans des ThreadGroup pour les synchroniser. Il a évidemment été nécessaire de refaire les Mutex pour utiliser le RAII. Mais je sais pas si j'oserais mettre le code (bien qu'il soit accessible au public), des spécialistes en programmation multi-thread ont déjà dû faire un équivalent plus complet que moi.

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 36
    Par défaut
    Merci encore pour ces réponses, j'ai regardé votre tuto sur Boost, mais il y a encore une chose que je ne comprend pas:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    // Une variable globale qui pourra être encapsulée au besoin
    boost::thread_specific_ptr<int> value;
    // Une variable globale avec son mutex, le tout devrait être dans une classe englobante
    std::vector<unsigned int> traitement;
    boost::mutex mutexTraitement;
    C'est ce passage, en fait je n'ai jamais vu ce type de code avant, ça sert à quoi? ça fait quoi?

    Et sinon pour faire plusieurs channel de discussion il faut créer plusieurs socket c'est ça (un par channel) ?

  13. #13
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    C'est sûr, il manque des choses, mais c'est le seul simple que je connaisse, autrement, il faut ajouter Qt ou autre.

    value est une variable différente pour chaque thread.
    mutexTraitement est simplement un mutex pour que l'accès à traitement soit unique et que plusieurs threads n'y accèdent pas en même temps. Si tu ne sais pas à quoi ça sert, relies les différents tutos

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 36
    Par défaut
    J'ai finalement décidé de m'orienter vers cette solution avec le select, mais j'aurais (encore ) plusieurs questions:

    Je me base sur ce anuel:

    http://www.linux-kheops.com/doc/man/.../select.2.html

    Là ils disent que pour les socket il faut écouter le exceptfds pour les socket et toi dans la fontion select tu as mis sur le readfds, qu'est-ce que ça change?

    Je comprend pas trop en fait l'utilisation, serait-ce possible d'avoir plus d'explications, par exemple est-ce que c'est compatible en C++? Je comprend pas l'utilisation de la liste, ça stocke tout les socket des clients? Si la réponse à la question précédente est vraie, serait-il possible de gérer des channel du chat avec un thread utilisant un select pour chaque channel? Comment obtient-on la première valeurdu select (ici maxfd)?
    Voila , merci d'avance pour les futures réponses.

    Citation Envoyé par millie
    Je pense que tu sais que dès que l'on fait intervenir des threads, ça devient très difficile à gérer (notamment les données partagées).

    Il est parfaitement possible de gérer plusieurs clients avec un seul processus/thread en utilisant select. Pourquoi ne pas utiliser cela ? Et utiliser des threads pour des opérations couteuses (le transfert d'un fichier où je ne sais quoi).

    Le code peut alors ressembler simplement à cela (c'est un code C) :

    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
    while(1)
      {
        maxfd = fdConnection+1;
        if(maxfd< STDIN_FILENO+1)
          maxfd = STDIN_FILENO+1;
     
        FD_ZERO(&setfd);
        FD_SET(fdConnection, &setfd);
        FD_SET(STDIN_FILENO, &setfd);
     
        /** repositionnement pour chaque client */
     
        clientListBegin();
        for(i = 0; i<clientListGetSize(); i++)
        {
          int lsocket = clientListGetSocket(i);
          FD_SET(lsocket, &setfd);
          if(lsocket+1>maxfd)
            maxfd = lsocket+1;
        }
        clientListEnd();
     
        if(select(maxfd, &setfd, 0,0,0) == -1)
        {
          perror("select");
          exit(EXIT_FAILURE);
        }
     
        if(FD_ISSET(STDIN_FILENO, &setfd))
        {
          fprintf(stderr, "Close program : \n");
          break;
        }
        /*on matte ce que les gens racontent*/
        clientListBegin();
        for(i = 0; i<clientListGetSize(); i++)
        {
          lsocket = clientListGetSocket(i);
          if(FD_ISSET(lsocket, &setfd))
          {
            //tailleget = read(lsocket, buffer, sizeof(buffer)-1);
            tailleget =  recv(lsocket, buffer, sizeof(buffer)-1, MSG_PEEK);
            if(tailleget == -1)
            {
              perror("recv");
              continue;
            }
     
            if(tailleget == 0)
            {
              fprintf(stderr, "Disconnection\n");
              close(lsocket);
              clientListPrepareToRemove(i);
              continue;
            }
     
            char *  realEnd;
     
            realEnd = memchr(buffer, '\n', tailleget);
            if(realEnd == NULL)
            {
              fprintf(stderr, "Server receive a too long packet\n");
              continue;
            }
     
            tailleget = realEnd - buffer + 1;
     
            tailleget = recv(lsocket, buffer, tailleget,0 );
     
     
            if(tailleget == -1)
            { /*n'arrivera jamais ici*/
              perror("recv");
            }
            else
            {
              /*fin de connexion ?*/  /*n'arrivera jamais ici*/
              if(tailleget == 0)
              {
                fprintf(stderr, "Disconnection...\n");
                close(lsocket);
                clientListPrepareToRemove(i);
              }
              else
              {
                buffer[tailleget] = '\0';
                printf(" * PACKET :  : %s\n", buffer);
                serverInterpreter(buffer, lsocket);
                DEBUG("End serverInterpreter");
              }
            }
          }
        }
        clientListEnd();
     
        DEBUG("debut demande de connexion");
     
     
        /* nouvelle demande de connexion ?*/
        if(FD_ISSET(fdConnection, &setfd))
        {
          fprintf(stderr, "Demande de connexion....\n");
          tailleaddr = sizeof addrClient;
          clientSocket = accept(fdConnection, (struct sockaddr*) &addrClient,
                                &tailleaddr);
          if(clientSocket == -1)
          {
            perror("accept");
            continue;
          }
          //fprintf(stderr, " * Port : %d", ntohs(addrClient.sin_port));
     
          if(clientListAdd(clientSocket, addrClient.sin_addr.s_addr, addrClient.sin_port) == -1)
          {
            fprintf(stderr, "Ajout client impossible\n");
          }
        }
     
        DEBUG("fin demande de connexion");
     
      }




    Ton implémentation de ta classe thread m'a l'air très mauvaise si tu ne dois faire une boucle infinie comme ça. En plus, une boucle infinie, c'est une attente active ce qu'il faut ne surtout pas faire !



    Cet argument n'est absolument pas valabe ! Il suffit d'utiliser select. Ta manière de raisonner suppose que ça peut bloquer dans un thread, donc que le thread dorme, mais qu'il soit toujours là ! C'est une très mauvaise solution. Ton serveur doit être capable de vivre pendant des journées, si tu as des threads qui dorment partout, ou des threads qui sont en attente actives, ça ne va pas le faire.

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    36
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 36
    Par défaut
    Bon, comme j'ai pas trouvé assez d'info sur le select et comme ça à l'air assez compliqué je suis retourné vers les threads, par contre j'aimerai savoir comment extraire des mots à partir d'un message.
    Par exemple la personne tape:
    join Channel1
    Là il faudrai voir qu'il y a "join" et "Channel1" donc ça appelle une foction "ConnectChannel" avec comme paramètre "Channel1", est-ce qu'il y a des fonction sspéciales pour ça?

Discussions similaires

  1. Ubuntu 11.10 sur Vmware : problème de multi-threading?
    Par khealou dans le forum Threads & Processus
    Réponses: 1
    Dernier message: 30/12/2012, 11h33
  2. Problèmes de multi-threading
    Par ToTo13 dans le forum Général Java
    Réponses: 10
    Dernier message: 20/06/2012, 15h36
  3. Réponses: 7
    Dernier message: 12/06/2011, 07h14
  4. Probléme serveur multi-thread
    Par hebus44 dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 14/11/2007, 22h32
  5. problme de multi thread
    Par L4BiN dans le forum Concurrence et multi-thread
    Réponses: 22
    Dernier message: 25/04/2007, 16h47

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