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 :

Socket : multiplexage et STREAM


Sujet :

Réseau C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur Full Stack
    Inscrit en
    Mars 2009
    Messages
    94
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Mars 2009
    Messages : 94
    Par défaut Socket : multiplexage et STREAM
    Bonjour à tous,

    Je suis actuellement en train d'essayer de faire communiquer deux programmes entre eux en C grâce à une socket STREAM. Pour une raison qui m'échappe, et malgré toutes mes recherches, je n'arrive pas à résoudre la partie multiplexage.

    Mon programme devrait se derouler ainsi : un duo connect - accept tout d'abord, la connexion étant faite, un recv et un send de chaque côté. Jusque là tout se passe comme il se doit.

    Derrière je souhaite mettre en place un multiplexage sur la socket et sur l'entrée clavier (0) afin que d'un côté comme de l'autre ils puissent envoyer des messages tout en étant capable d'en recevoir. Or mon select sur la socket STREAM ne semble pas du tout vouloir recevoir de données (sur l'entrée clavier pas de soucis, mais les send() ne semblent pas provoquer le select de l'autre côté et donc la réception.

    Voici le code associé (enfin le bout de code pour plus de légéreté, car le programme ne fait pas que ça, mais il s'agit ici d'une partie indépendante du programme) :

    Celui qui déclenche le connect() le fait à travers cette fonction :
    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
     
    void envoyerDemande(int numClient, char *buffEnvoi){
      // Socket
      int sstreamclient;
      struct sockaddr_in struct_sstreamclient;
      // Variables
      int n;
      char buffReception[MAXBUFF];
      memset(buffReception, 0, MAXBUFF);
      fd_set conversation_readmask; // File descriptor
     
      sstreamclient = socket(AF_INET, SOCK_STREAM, 0);
      CHECK(sstreamclient, "Erreur de création socket");
     
      // Détails de la socket cliente
      struct_sstreamclient.sin_family = AF_INET;
      struct_sstreamclient.sin_port = htons(listeClients.clients[numClient].port);
      struct_sstreamclient.sin_addr.s_addr = inet_addr(listeClients.clients[numClient].IP);
      bzero(struct_sstreamclient.sin_zero, 8);
      printf("\nDemande de connexion en cours, attente de la réponse\n");
      printf("Infos client : %s:%d\n", listeClients.clients[numClient].IP, listeClients.clients[numClient].port);
     
      /**
      * Connexion au client
      */
      // Envoi des informations de connexion
      CHECK (connect( sstreamclient, (struct sockaddr *)&struct_sstreamclient, sizeof(struct_sstreamclient)), "Erreur d'acceptation d'une connexion TCP\n");
      //CHECK(send( sstreamclient, buffEnvoi, strlen(buffEnvoi), 0, (struct sockaddr *)&struct_sstreamclient, sizeof(struct_sstreamclient)), "Problème d'écriture\n");
      CHECK(send(sstreamclient, buffEnvoi, strlen(buffEnvoi), 0), "Problème d'écriture\n");
      // ACK 
      memset(buffReception, 0, MAXBUFF);
      CHECK (recv(sstreamclient, buffReception, sizeof(buffReception), 0), "Problème de lecture\n" );
      // Vérification
      printf("# %s\n", buffReception);
      // Attente de la réponse du client
      switch(verifRequeteRecu(buffReception)){
    	case 2 : // OUI
    		 printf("Reponse oui : %s\n", buffReception);
     
    		 /**
                     * Conversation
                     */
    		 // system("clear");
    		printf("\n\n#######################################\n\n");
    		printf("Conversation avec %s : %s:%d\n", listeClients.clients[numClient].nom, listeClients.clients[numClient].IP, listeClients.clients[numClient].port);
    		printf("Tapez '/quit' pour quitter la conversation\n");
    		printf("\n#######################################\n\n");
     
    		/**
                    * Multiplexage
                    */
    		FD_ZERO(&conversation_readmask); // Vide l'ensemble de lecture
    		FD_SET(0, &conversation_readmask); // Clavier
    		FD_SET(sstreamclient, &conversation_readmask); // Ecoute
     
    		while(1){
    		  /**
                      * Conversation
                      */
    		  fflush(stdin);
     
    		  // Attente d'une entrée clavier ou de la réception sur la socket d'écoute
    		  FD_ZERO(&conversation_readmask); // Vide l'ensemble de lecture
    		  FD_SET(0, &conversation_readmask); // Clavier
    		  FD_SET(sstreamclient, &conversation_readmask); // Ecoute
     
    		  CHECK(n = select(4, &conversation_readmask, NULL, NULL, NULL), "Erreur de select\n");
     
    		  if(n > 0 && FD_ISSET(sstreamclient, &conversation_readmask)){
    		    /**
                        * Reception sur la socket d'ecoute
                        */
    		    printf("RECEPTION CONVERSATION\n");
    		    memset(buffReception, 0, MAXBUFF);
    		    CHECK (recv(sstreamclient, buffReception, sizeof(buffReception), 0), "Problème de lecture\n" );
    		    printf("%s : %s\n", listeClients.clients[numClient].nom, buffReception);
    		  }
    		  else if(n > 0 && FD_ISSET(0, &conversation_readmask)){
    		    /**
                        * Entrée clavier
                        */
    		    //printf("EMISSION CONVERSATION\n");
    		    // Choix
    		    memset(buffEnvoi, 0, MAXBUFF);
    		    printf(">> ");
    		    scanf("%s", buffEnvoi);
    		    printf("Vous : %s\n", buffEnvoi);
    		    //sprintf(buffEnvoi, "/CON#!#%s#!#%s#!#%d#!#\0", nomUtilisateur, getMonAdresseIp(), getMonPort(sstreammoi, struct_sstreammoi)); // user, IP, port
    		    CHECK(send(sstreamclient, buffEnvoi, strlen(buffEnvoi), 0), "Problème d'écriture\n");
    		    printf("SEND\n");
    		  }
     
    		}
     
    		 break;
    	case 3 : // NON
    		 printf("Reponse non : %s\n", buffReception);
    		 break;
    	default : printf("Erreur reponse %d\n", verifRequeteRecu(buffReception)); break;
          }
    }
    De l'autre côté, il y a multiplexage sur une socket d'ecoute 'sstreammoi', ce qui déclenche un accept et donc la création d'une socket 'sclt' - sclt = accept(...) - et j'aimerais lancer un nouveau multiplexage (dans un while(1) pour le moment mais ça changera plus tard pour la condition) sur sclt pour pouvoir des recv et send comme je le souhaite :
    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
     
    // Attente d'une entrée clavier ou de la réception sur la socket d'écoute
        FD_ZERO(&readmask); // Vide l'ensemble de lecture
        FD_SET(0, &readmask); // Clavier
        FD_SET(sstreammoi, &readmask); // Ecoute
     
        CHECK(n = select(4, &readmask, NULL, NULL, NULL), "Erreur de select\n");
     
        if(n > 0 && FD_ISSET(sstreammoi, &readmask)){
          /**
          * Reception sur la socket d'ecoute
          */
          lensstreammoi = sizeof(struct_sstreammoi);
          CHECK (sclt = accept( sstreammoi, (struct sockaddr *)&struct_sstreammoi, &lensstreammoi), "Erreur d'acceptation d'une connexion TCP\n");
          memset(buffReception, 0, MAXBUFF);
          CHECK (recv(sclt, buffReception, sizeof(buffReception), 0), "Problème de lecture\n" );
          printf("Message reçu : %s\n", buffReception);
          switch(verifRequeteRecu(buffReception)){
    	case 1 : // DEMANDE
    		printf("Demande de la liste des connectes\n");
    		memset(buffEnvoi, 0, MAXBUFF);
    		sprintf(buffEnvoi, "/LISTE#!#%s#!#%s#!#%d#!#\0", nomUtilisateur, getMonAdresseIp(), getMonPort(sstreammoi, struct_sstreammoi)); // user, IP, port
    		recevoirListeClients(sdgramserveur, struct_sdgramserveur, buffEnvoi); // Necessaire de rafraichir la liste pour quel le nombre de clients soit à jour
     
    		printf("L'utilisateur suivant :\n");
    		numClient = chercherUtilisateur(buffReception);
    		printf("souhaite rentrer en contact avec vous. Accepter ? \n    1. Oui\n    2. Non\nEntrez votre sélection :\n");
    		scanf("%d", &choix);
    		if(choix){
    		  // Acceptation
    		  memset(buffEnvoi, 0, MAXBUFF);
    		  sprintf(buffEnvoi, "/YESDMD#!#%s#!#%s#!#%d#!#\0", nomUtilisateur, getMonAdresseIp(), getMonPort(sstreammoi, struct_sstreammoi)); // user, IP, port
    		  CHECK(send(sclt, buffEnvoi, strlen(buffEnvoi), 0), "Problème d'écriture\n");
    		  CHECK(numClient, "Problème de numClient\n");
     
    		  /**
                      * Conversation
                      */
    		  // system("clear");
    		  printf("\n\n#######################################\n\n");
    		  printf("Conversation avec %s : %s:%d\n", listeClients.clients[numClient].nom, listeClients.clients[numClient].IP, listeClients.clients[numClient].port);
    		  printf("Tapez '/quit' pour quitter la conversation\n");
    		  printf("\n#######################################\n\n");
     
    		  /**
                      * Multiplexage
                      */
    		  FD_ZERO(&conversation_readmask); // Vide l'ensemble de lecture
    		  FD_SET(0, &conversation_readmask); // Clavier
    		  FD_SET(sclt, &conversation_readmask); // Ecoute
     
    		  while(1){
    		    /**
                        * Conversation
                        */
    		    fflush(stdin);
     
    		    // Attente d'une entrée clavier ou de la réception sur la socket d'écoute
    		    FD_ZERO(&conversation_readmask); // Vide l'ensemble de lecture
    		    FD_SET(0, &conversation_readmask); // Clavier
    		    FD_SET(sclt, &conversation_readmask); // Ecoute
     
    		    CHECK(n = select(4, &conversation_readmask, NULL, NULL, NULL), "Erreur de select\n");
    		    printf("n VAUT %d\n", n);
     
    		    if(n > 0 && FD_ISSET(sclt, &conversation_readmask)){
    		      /**
                          * Reception sur la socket d'ecoute
                          */
    		      printf("RECEPTION CONVERSATION\n");
    		      memset(buffReception, 0, MAXBUFF);
    		      CHECK (recv(sclt, buffReception, sizeof(buffReception), 0), "Problème de lecture\n" );
    		      printf("%s : %s\n", listeClients.clients[numClient].nom, buffReception);
    		    }
    		    else if(n > 0 && FD_ISSET(0, &conversation_readmask)){
    		      /**
                          * Entrée clavier
                          */
    		      printf("EMISSION CONVERSATION\n");
    		      // Choix
    		      memset(buffEnvoi, 0, MAXBUFF);
    		      scanf("%s", buffEnvoi);
    		      printf("Vous : %s\n", buffEnvoi);
    		      //sprintf(buffEnvoi, "/CON#!#%s#!#%s#!#%d#!#\0", nomUtilisateur, getMonAdresseIp(), getMonPort(sstreammoi, struct_sstreammoi)); // user, IP, port
    		      CHECK(send(sclt, buffEnvoi, strlen(buffEnvoi), 0), "Problème d'écriture\n");
    		      printf("SEND\n");
    		    }
     
    		  }
     
    		}
    		else{
    		  // Refus
    		  // Acceptation
    		  memset(buffEnvoi, 0, MAXBUFF);
    		  sprintf(buffEnvoi, "/NODMD#!#%s#!#%s#!#%d#!#\0", nomUtilisateur, getMonAdresseIp(), getMonPort(sstreammoi, struct_sstreammoi)); // user, IP, port
    		  CHECK(send(sclt, buffEnvoi, strlen(buffEnvoi), 0), "Problème d'écriture\n");
    		}
    		break;
    	default : printf("Erreur de requete"); break;
          }
          choix = -1;
        }
    (... suite des if sur le premier multiplexage)
    Avez-vous une idée du problème ?

    Je vous remercie,

  2. #2
    Membre confirmé
    Homme Profil pro
    Développeur Full Stack
    Inscrit en
    Mars 2009
    Messages
    94
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Mars 2009
    Messages : 94
    Par défaut
    L'un de vous a-t-il une idée ?

  3. #3
    Membre émérite Avatar de |PaRa-BoL
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Novembre 2003
    Messages : 738
    Par défaut
    Le mieux est de mettre tes sockets en mode "non bloquants" (aussi bien pour le socket d'écoute que pour les clients) :

    i.e.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #define setnonblocking(fd) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK)
    Tu te complique un peu la vie avec tout tes "select()".

    Le principe (simplifié) est le suivant :

    Server :

    - création du socket d'écoute (bind() & listen())
    - setnonblocking(fd server)
    - boucle autour de select() des évènements read/write
    - Si event read sur fd server => accept() => setnonblocking(fd client)
    - Si event read sur fd client => read()
    Pour la partie client :

    - création du socket
    - setnonblocking(fd)
    - connection au server (connect()) <= va retourner une erreur EINPROGRESS
    - boucle autour de select() des évènements read/write
    - si event write et que le dernier statue du fd est EINPROGRESS (et pas d'erreur sur getsockopt([...]SOL_SOCKET, SO_ERROR[...])) => connexion réussie
    - si event read => read()
    Tu peux bien sûr mêler STDIN à tout ça pour gérer les entrés

    En résumé :

    - 1 seul select()
    - possibilité d'avoir plusieurs clients connectés

  4. #4
    Membre confirmé
    Homme Profil pro
    Développeur Full Stack
    Inscrit en
    Mars 2009
    Messages
    94
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Full Stack

    Informations forums :
    Inscription : Mars 2009
    Messages : 94
    Par défaut
    Bonjour PaRa-BoL et joyeuses fêtes à vous,

    Une réponse complète, je ne connaissais pas la fonction fcntl(). Un petit soucis peut-être, le fonctionnement de mon programme se fait ainsi :

    - le serveur gère une liste de connectés, les clients disent au serveur via une socket DGRAM (je me connecte).
    - les clients ont une socket d'écoute STREAM, avec un bind fait dessus dès le démarrage. Ils envoient au serveur les informations de cette socket, ce sont ces information qui sont contenues dans la liste (nom du client, IP, port)
    - les clients peuvent recevoir cette liste (toujours en UDP) et dire je me connecte à un autre client pour lui parler (et donc connect sur la socket STREAM d'un autre client).

    C'est pourquoi j'ai deux select(), un qui ecoute la socket en UDP, et l'autre. Mais je vais tenter d'implementer votre solution non bloquante.

    Merci pour vos conseils,

Discussions similaires

  1. fuite de memoire, socket et Stream
    Par kuguy dans le forum Entrée/Sortie
    Réponses: 8
    Dernier message: 06/03/2008, 09h06
  2. [Socket&Stream] Plusieurs streams sur une même socket
    Par Napalm51 dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 15/11/2007, 15h40
  3. event sur des streams de socket
    Par quicky2000 dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 02/11/2007, 16h34
  4. Utilisation de select (multiplexage de socket)
    Par caesarvanou dans le forum C++
    Réponses: 5
    Dernier message: 12/07/2006, 15h45
  5. Transfert d'une image par socket stream
    Par francky23012301 dans le forum Langage
    Réponses: 1
    Dernier message: 31/10/2005, 16h06

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