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 :

Client/serveur : ouvrir une deuxième connexion


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 56
    Par défaut Client/serveur : ouvrir une deuxième connexion
    Bonjour,

    Je suis en train d'écrire un chat. Pour le moment plusieurs clients peuvent se connecter et discuter : tout va bien. Mais les utilisateurs doivent aussi pouvoir créer des groupes de discussion avec une commande creategroup nom_du_gpe membre1 membre2 membre3. Le serveur doit alors demander à membre1 membre2 et membre3 s'ils veulent entrer dans le groupe, et c'est là que ça se corse pour moi. Ce que j'ai fait pour le moment :

    • Côté serveur : Pour chaque membre, je crée un thread. Dans chaque thread j'envoie un message "voulez vous faire partie du groupe ? (o/n)". Mais pour récupérer la réponse, je ne peux pas utiliser la socket client déjà connectée au serveur parce qu'elle est déjà lue périodiquement dans le main() de mon programme... Il faut donc que j'ouvre une nouvelle connexion spécialement pour cette requête. J'ouvre donc une nouvelle socket et j'attends que le client se connecte.
    • Côté client : quand le client reçoit "voulez-vous faire partie du groupe ? (o/n)", il crée une nouvelle socket pour envoyer sa réponse. Problème : comment faire pour que cette socket se connecte précisément à celle que vient d'ouvrir le serveur ?

    La question se pose aussi côté serveur : j'ouvre trois thread dans lesquels j'ouvre une socket. Comment être sûr que la socket à laquelle est destiné un client précis acceptera bien une connexion de ce client et non d'un autre ?

    J'espère que ça ne parait pas trop confus. Peut-être aussi que je fais fausse route et qu'il y a un moyen plus simple de réaliser cette demande de confirmation.

    Merci d'avance pour vos réponses.

  2. #2
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Tu peux effectivement faire de la discrimination sur les adresses serveur et cliente lorsque tu gères tes sockets mais, d'une manière générale, l'exercice consiste normalement à ouvrir d'abord la connexion, à dialoguer avec le client pour lui permettre éventuellement de s'authentifier et, enfin, de l'orienter vers le bon groupe ou mettre fin à la connexion s'il y a lieu.

    Tu peux également lire cette discussion, qui traitait d'un sujet similaire : http://www.developpez.net/forums/d10...ert-lutiliser/

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 56
    Par défaut
    Bonjour,

    Merci pour la réponse. Je vais regarder le sujet en question. Sinon l'exercice n'est pas tout à fait l'exercice classique en fait : les clients qui se connectent ne sont pas affectés à un groupe. Ils sont dans le "groupe par défaut" si je puis dire, et c'est ensuite qu'ils peuvent créer de nouveaux groupes ou intégrer des groupes existants. Ils peuvent même intégrer plusieurs groupes différents. Pour communiquer avec un groupe ils doivent taper la commande nom_du_groupe message[...]

    Je vous tiens au courant

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 56
    Par défaut
    J'avoue que je ne comprends pas trop en quoi le fil que tu m'as donné en lien pourrait m'aider :s Sinon j'ai peut-être trouvé une solution : ouvrir une connexion sur un nouveau port à chaque fois que le serveur veut demander une confirmation... Mais ça me parait un peu crade, si j'ai beaucoup de clients le serveur va être obligé d'ouvrir temporairement des connexion sur un paquet de ports non ? Pourrais-tu m'en dire plus sur ce que tu appelles la discrimination d'adresse stp ? Ça à l'air intéressant mais j'ai pas trouvé de doc à ce sujet...

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Chercheur d'emploi
    Inscrit en
    Septembre 2007
    Messages
    7 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur d'emploi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 487
    Par défaut
    Citation Envoyé par silma Voir le message
    J'avoue que je ne comprends pas trop en quoi le fil que tu m'as donné en lien pourrait m'aider :s
    Il faut la lire jusqu'au bout : le fil démarre sur la meilleure manière de vérifier si un programme est déjà ouvert et se termine par l'écriture d'un mini-serveur IRC-like.

    C'est intéressant également parce qu'il gère n clients en n'utilisant qu'un seul thread.

    Sinon j'ai peut-être trouvé une solution : ouvrir une connexion sur un nouveau port à chaque fois que le serveur veut demander une confirmation... Mais ça me parait un peu crade, si j'ai beaucoup de clients le serveur va être obligé d'ouvrir temporairement des connexion sur un paquet de ports non ? Pourrais-tu m'en dire plus sur ce que tu appelles la discrimination d'adresse stp ? Ça à l'air intéressant mais j'ai pas trouvé de doc à ce sujet...
    C'est effectivement très sale.

    En plus, c'est faire l'hypothèse que tu travailles forcément en TCP/IP, ce qui est généralement le cas aujourd'hui, mais pas forcément.

    Ensuite, il faut éviter de recourir systématiquement aux threads et à la multiplication des processus, car ils sont coûteux en ressources et, souvent, le signe que quelque chose n'est pas maîtrisé en amont (en tout cas, dans le genre de cas de figure qui nous intéresse aujourd'hui).

    La meilleure manière de procéder est de créer un objet « connexion » (une simple structure suffit) et en créer une instance par client entrant. Cette structure contiendrait alors toutes les infos relatives à une connexion, comme son descripteur de socket, mais également, par exemple, le numéro du groupe dont le client fait partie, en considérant par exemple que le groupe « zéro » existerait toujours et contiendrait justement tous les clients qui ne sont pas affectés à un autre groupe.

    De là, tu continues à exploiter ton code habituel. J'imagine qu'en l'état actuel des choses, chaque fois que quelqu'un poste un message, tu passes en revue toutes les connexions ouvertes pour leur envoyer, une par une, le message en question. Il te suffit donc de faire exactement la même chose mais en vérifiant si le numéro du groupe du connecté est le même que celui de la personne qui a envoyé le message.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    56
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 56
    Par défaut
    La meilleure manière de procéder est de créer un objet « connexion » (une simple structure suffit) et en créer une instance par client entrant. Cette structure contiendrait alors toutes les infos relatives à une connexion, comme son descripteur de socket, mais également, par exemple, le numéro du groupe dont le client fait partie, en considérant par exemple que le groupe « zéro » existerait toujours et contiendrait justement tous les clients qui ne sont pas affectés à un autre groupe.
    Yeaaah ! C'est plus ou moins ce que j'ai fait : une structure "Client" avec un numéro de groupe, une socket "normale" qu'il utilise lors de sa connexion, et un pseudo.

    J'imagine qu'en l'état actuel des choses, chaque fois que quelqu'un poste un message, tu passes en revue toutes les connexions ouvertes pour leur envoyer, une par une, le message en question. Il te suffit donc de faire exactement la même chose mais en vérifiant si le numéro du groupe du connecté est le même que celui de la personne qui a envoyé le message.
    Oui effectivement c'est plus joli comme ça. Mais comme au départ le client appartient au groupe 0, il faut bien que le serveur lui demande s'il veut rejoindre le group n par exemple. Et pour ça je suis obligé de créer un nouveau thread et une nouvelle connexion avec le client, que je clos dès que le serveur à reçu la confirmation, non ? (au passage j'ai ajouté un champs "socket temporaire" dans la structure client pour réaliser cette seconde connexion). En tout cas c'est comme ça que je suis en train de faire et ça avance plutôt pas trop mal.

    EDIT : ça avance pas trop mal, mais je bloque quand même sacrément là, sur la fonction FD_SET. J'ai l'impression qu'au lieu d'ajouter une socket à mon ensemble rdfs, elle écrase la précédente socket...

    Je mets le code, j'espère que ce sera compréhensible bien que ce ne soit qu'un "bout de code" du programme...
    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
     
    La fonction thread qui me permets de créer mes groupes
    void * groupCreationThreadFun(void* data){
     
      Data * pData = (Data*)data;
      char buffer[BUF_SIZE];
      int nbOfAnswers = 0; //compte le nombre de clients qui ont déjà répondu à la requete
      int max=0; // pour la selection de socket
     
      SOCKET sock = init_connection(PORT+1); // création de la socket de connexion du serveur
      fd_set readset;
      FD_ZERO(&readset);
     
     
      for (int i=0 ; i< pData->nbOfGuests ; i++){ //j'établis une connexion avec chacun des clients concernés
     
        SOCKET csock;
        SOCKADDR_IN csin = { 0 };
        socklen_t csinsize = sizeof(csin);
     
        /* création de la demande au client */
        char * question = malloc(200);
        strcpy(question,"joingroup voulez-vous rejoindre le groupe "); //le mot-clé "joingroup me permet de détecter qu'il s'agit d'une requete pour rejoindre un groupe côté client
        strcat(question,pData->group.name);
        strcat(question," ?");
        /* envoi de la demande au client */
        write_client(pData->guests[i]->sock,question); 
        /* attente de la connexion du client */
        csock = accept(sock, (SOCKADDR *)&csin, &csinsize); 
        if(csock == SOCKET_ERROR)
          perror("accept()");
        /* on mémorise la socket pour la suite */
        pData->guests[i]->tempSock = csock;
     
     
       /* On ajoute la socket du client à readset,
    mais j'ai l'impression que ça foire un peu... */
        FD_SET(pData->guests[i]->tempSock,&readset); 
        max = csock > max ? csock : max; // calcul du nouveau max, pour le select
      }
     
      while(nbOfAnswers < pData->nbOfGuests){ // On attend que tous les clients aient répondu à la requete
     
    /* ci ça bloque au deuxième passage dans la boucle, car readset ne contient plus rien... 
    En tout cas quand je débug avec gdb, print readset renvoit {__fds_bits = {0 <repeated 16 times>}
    J'ai l'impression que c'est FD_SET qui écrase la première socket au lieu d'en ajouter une nouvelle.*/
        printf("ca bloque au select...\n)"); 
        if(select(max , &readset, NULL, NULL, NULL) == -1){
          perror("select()");
          exit(errno);
        }
     
        for(int i = 0; i < pData->nbOfGuests; i++){
          /* on test quel client a répondu */
          if(FD_ISSET(pData->guests[i]->tempSock, &readset)){
     
    	read_client(pData->guests[i]->tempSock, buffer);
    	  if( strcmp(buffer,"yes") == 0){
    	    write_client(pData->guests[i]->tempSock,"You have been added to the group\n");
    	    strcpy(buffer,pData->guests[i]->name);
    	    strcat(buffer," accepted the invitation to your group");
    	    write_client(pData->creator.sock,buffer);
    	  }
    	  if( strcmp(buffer,"no") == 0 ){
    	    strcpy(buffer,pData->guests[i]->name);
    	    strcat(buffer," refused the invitation to your group");
    	    write_client(pData->creator.sock,buffer);
    	  }
    	  /* Je déconnecte le client qui vient de répondre */
    	  FD_CLR(pData->guests[i]->tempSock,&readset);
    	  closesocket(pData->guests[i]->tempSock);nbOfAnswers++;
    	  printf("On ferme la socket du client %s\n",pData->guests[i]->name);
          }
        }
     }
      closesocket(sock);
      return NULL;
    }
    Merci beaucoup pour toutes ces précisions

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 18/09/2016, 12h46
  2. Client/Serveur en Local sans connexion réseau
    Par ramoud dans le forum C++Builder
    Réponses: 8
    Dernier message: 05/07/2007, 14h44
  3. Problème lors d'une deuxième connexion à l'applet
    Par luckyvae dans le forum Applets
    Réponses: 3
    Dernier message: 16/03/2007, 10h21
  4. abstraction de client /serveur dans une application
    Par Pegaz dans le forum Développement
    Réponses: 2
    Dernier message: 24/01/2007, 09h30
  5. [VB2005]obliger windows à ouvrir une deuxième instance d'excel
    Par Gilles_37 dans le forum Windows Forms
    Réponses: 5
    Dernier message: 12/10/2006, 05h23

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