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 :

Problème simple de receive : plusieurs read ?


Sujet :

Réseau C

  1. #1
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut Problème simple de receive : plusieurs read ?
    Bonjour à tous,

    J'ai un bête problème : j'envoie une commande à un serveur et il me répond. Le problème provient du fait qu'il m'envoie sûrement plusieurs packet. Dans mon code je ne fait que un read, donc je n'ai pas la totalité du message.

    Comment puis-je modifier mon code pour avoir la totalité de la réponse ?

    Voici mon code :
    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
    bool client :: recive (char* host, char* service, char* packet, int packetSize)
    {
      char buff[BUFFER_SIZE];
      for(int i=0; i<BUFFER_SIZE; i++) 
      	buff[i] = '\0';
      buff[1] = '\0';
      int sock;
      int length;
      sock = connectTCP (host, service);  // or connectUDP
      if(sock < 0)
    	  return false;
      write (sock, packet, packetSize);
      length = read (sock, buff, sizeof(buff));
      close (sock);
      if (length < 0)
      {
    	  //cerr << _NET_ERR_ << "read failed: ";// << strerror(errno) << "\n";
    	  cout << "*** client::recive > Read failed." << endl;
    	  return false;
      }
      buff[length] = '\0';
      if (recived != NULL)
        delete recived;
      recived = NULL;
      recived = new char [length+1];
      assert (recived != NULL);
      memcpy(recived, buff, length+1);
      return true;
    }
    J'imagine faire un while avec un select, mais je ne sais pas trop comment faire sans que mon processus se mette en sleep dès qu'il n'y a plus rien à lire...

  2. #2
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    J'ai oublié de signalé que je suis sous linux.

    Je cherche depuis tout à l'heure, mais je n'y arrive pas...
    Il faudrait que je mette mon read dans un while et que le while s'arrête quand tout les packets ont été lus.

    j'essaye donc un truc du style :
    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
    bool client :: recive (char* host, char* service, char* packet, int packetSize)
    {
      char buff[BUFFER_SIZE];
      for(int i=0; i<BUFFER_SIZE; i++) 
      	buff[i] = '\0';
      int sock;
      int length;
      sock = connectTCP (host, service);  // or connectUDP
      if(sock < 0)
    	  return false;
      write (sock, packet, packetSize);
     
      int totalLenght = 0;
      char* totalBuff = NULL;
      do
      {
    	  length = read (sock, buff, sizeof(buff));
    	  if(length < 0)
    		  return false;
     
    	  int oldTotalLenght = totalLenght;
    	  cout << "oldTotalLenght = "<< oldTotalLenght << endl;
    	  totalLenght += length;
    	  cout << "totalLenght = "<< totalLenght << endl << endl;
     
    	  char* newBuff = new char [totalLenght+1];
    	  memcpy(newBuff, totalBuff, oldTotalLenght); // copy old datas
    	  for(unsigned i=oldTotalLenght, j=0; j<sizeof(buff); i++, j++) // copy new datas
    		  newBuff[i] = buff[j];
    	  delete totalBuff;
    	  totalBuff = newBuff;
    	  //delete newBuff;
     
    	  if(buff[BUFFER_SIZE-1] == '\0') // everything has been read.
    		  break;
      }
      while(true);
      close (sock);
      cout << "totalLenght final = " << totalLenght << endl;
     
      if (recived != NULL)
        delete recived;
      recived = NULL;
      recived = new char [totalLenght+1];
      assert (recived != NULL);
      memcpy(recived, totalBuff, totalLenght+1);
     
      return true;
    }
    Ca a l'air de marcher..

  3. #3
    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 : 61
    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
    Points : 50 367
    Points
    50 367
    Par défaut
    Le débat d'experts sur l'utilisation de send() et recv() ou read() et write() sur un socket a été déplacé dans une nouvelle discussion : Sur un socket : send et recv ou read et write ?.

    Merci de ne pas perdre de vue la question initiale

  4. #4
    Membre confirmé Avatar de dapounet
    Profil pro
    Étudiant
    Inscrit en
    Juillet 2007
    Messages
    469
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juillet 2007
    Messages : 469
    Points : 567
    Points
    567
    Par défaut
    Bonjour,

    Citation Envoyé par Colbix Voir le message
    Il faudrait que je mette mon read dans un while et que le while s'arrête quand tout les packets ont été lus.
    Je crois que je mettrais la taille du message au début de chaque message. À la réception il suffirait de lire la taille du message, puis boucler jusqu'à ce que le reste soit lu.

  5. #5
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Moi j'aurais plutôt gérer ça avec des I/O non bloquantes, en faisant un read jusqu'à EAGAIN, mais le fait ce coupler ça à la méthode de dapounet semble plus logique étant donner que tu passes des commandes, mieux vaut avoir la commande entière ;-).

  6. #6
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    Merci pour vos réponses.

    Maintenant je gère ca avec un select.
    Le problème c'est que j'ai toujours des timeout alors que le serveur envoie des données. Si je retire ce qui est en rouge dans mon code (voir ci dessous), ca marche nickel sauf quand le serveur ne m'envoie rien évidemment... Le processus se met en sleep.

    Ou est l'erreur ?

    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
    char *
    Dp_RPC(DPServer server, char* mesgStr, struct timeval* tv, int* errorPtr)
    {
        int rc, len;
        int amtRecv = -1, totalAmt = 0;
    
        *errorPtr = 0;
    
        /*
         * Send the RPC to the remote server.  Note the 12 is
         * just a random ID since we don't use IDs.
         */
        rc = SendRPCMessage(server, TOK_RPC, 12, mesgStr);
        if (rc <= 0) {
        	*errorPtr = errno;
        	strcpy(retStr, "Error writing on socket");
        	return retStr;
        }
    
        /*
         * Now we want to recv the reply.
         * We spin in a loop waiting for the entire message
         * to arrive.  This gets a bit messy.
         */
        bufPtr = retStr;
        while (amtRecv < totalAmt) {
        	char lengthStr[7];
    
        	rc = Dp_WaitForServer(server, tv);
    	    if (rc <= 0) {
    		    if (rc == 0) {
    			*errorPtr = -1;
    			strcpy(retStr, "RPC timed out");
    			return retStr;
    		    } else {
    			*errorPtr = errno;
    			strcpy(retStr, "Select error");
    			return retStr;
    		    }
    		}    	 
    	
    	amtRecv = recv(server, bufPtr, (retStr + DP_BUFFER_SIZE) - bufPtr, 0);
    	if ((amtRecv >= 6) && (totalAmt == 0)) {
    	    /*
    	     * Extract the length field from the incoming message
    	     * so we know when we have recv'd the entire message.
    	     */
    	    strncpy(lengthStr, retStr, 6);
    	    lengthStr[6] = '\0';
    	    totalAmt = atoi(lengthStr);
    	} else if (amtRecv == 0) {
    	    /*
    	     * EOF
    	     */
    	     break;
    	}
    	bufPtr += amtRecv;
        }
    
        if (retStr[7] == 'x') {
        	*errorPtr = -1;
        }
        len = totalAmt - 16;
        memcpy(retStr, &retStr[16], len);
        retStr[len] = '\0';
        return retStr;
    }
    Voici la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int
    Dp_WaitForServer(DPServer server, struct timeval* tv)
    {
        fd_set readFD;
     
        FD_ZERO(&readFD);
        FD_SET(server, &readFD);
        return select(1, &readFD, NULL, NULL, tv);
    }
    tv est initialisé comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	this->tv.tv_sec = 3;
    	this->tv.tv_usec = 0;
    Si vous avez des idées, je suis prenneur !

    Merci d'avance

  7. #7
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Je n'ai pas regardé ton code, en revanche, je te déconseille la fonction select(), sauf si tu es sous Windows et que tu veux être portable.

  8. #8
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    Coucou,

    Comment gérerais-tu le time-out alors ?

  9. #9
    Membre émérite Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Points : 2 280
    Points
    2 280
    Par défaut
    Citation Envoyé par Colbix Voir le message
    Coucou,

    Comment gérerais-tu le time-out alors ?
    En portable, j'utiliserai dans l'ordre pselect() ou poll(), en non portable, j'utiliserai dans l'ordre epoll_wait(), ppoll(), epoll_pwait(). Les fonctions non portables sont qui plus est, plus puissantes et plus sécurisées.

  10. #10
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    Ok, je regarderai ces fonctions, merci du tuyau .

    Je ne comprend quand même pas pourquoi mon code n'est pas correcte... Et pourquoi j'ai que des time-outs...

    A+

  11. #11
    Expert éminent sénior

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

    Informations forums :
    Inscription : Janvier 2007
    Messages : 10 610
    Points : 17 923
    Points
    17 923
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Colbix Voir le message
    Je ne comprend quand même pas pourquoi mon code n'est pas correcte... Et pourquoi j'ai que des time-outs...
    ram-000 t'a donné les pointeurs...


    @nicolas : malheureusement poll n'est pas portable...

  12. #12
    Expert éminent sénior
    Avatar de Emmanuel Delahaye
    Profil pro
    Retraité
    Inscrit en
    Décembre 2003
    Messages
    14 512
    Détails du profil
    Informations personnelles :
    Âge : 67
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2003
    Messages : 14 512
    Points : 20 985
    Points
    20 985
    Par défaut
    Citation Envoyé par Colbix Voir le message
    Ou est l'erreur ?

    Voici la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int
    Dp_WaitForServer(DPServer server, struct timeval* tv)
    {
        fd_set readFD;
     
        FD_ZERO(&readFD);
        FD_SET(server, &readFD);
        return select(1, &readFD, NULL, NULL, tv);
    }
    tv est initialisé comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    	this->tv.tv_sec = 3;
    	this->tv.tv_usec = 0;
    Erreur classique... Il faut initialiser tv avant chaque appel de select().

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int Dp_WaitForServer(DPServer server)
    {
       fd_set readFD;
       struct timeval tv;
     
       FD_ZERO(&readFD);
       FD_SET(server, &readFD);
     
       tv.tv_sec = 3;
       tv_usec = 0;
     
        return select (1, &readFD, NULL, NULL, &tv);
    }
    Nota : ce '1' est horrible. On ne sait pas de quoi il s'agit... Il fait mettre une valeur > à la plus grande valeur des descripteurs surveillés. Bien lire la doc de select().

    http://www.opengroup.org/onlinepubs/...ns/select.html

    Ceci peut aider :

    http://emmanuel-delahaye.developpez....reseaux-c/#LVI

  13. #13
    Membre habitué Avatar de Colbix
    Profil pro
    Développeur Web
    Inscrit en
    Juin 2006
    Messages
    266
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Juin 2006
    Messages : 266
    Points : 150
    Points
    150
    Par défaut
    Coucou,

    Grand merci pour vos réponses !

    Le problème venait en effet du 1... Ca m'apprendra à repiquer du code sans tout relire.

    Ca marche parfaitement maintenant. Je vais tout de même changer ce select.

    Merci encore !!!

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

Discussions similaires

  1. Problème simple avec des checkbox
    Par nanor21 dans le forum Langage
    Réponses: 2
    Dernier message: 07/05/2006, 00h26
  2. [débutant] Problème de liaison un à plusieurs
    Par Anthony17 dans le forum Access
    Réponses: 7
    Dernier message: 02/05/2006, 14h11
  3. [Javadoc]La Javadoc et un problème... simple mais paralysant
    Par lionrouge dans le forum Eclipse Java
    Réponses: 2
    Dernier message: 09/12/2005, 00h00
  4. Problème simple d'apostrophe qui m'ennerve !
    Par beletteroi dans le forum Requêtes
    Réponses: 1
    Dernier message: 10/09/2005, 21h58
  5. Problème requête qui renvoie plusieurs
    Par dai.kaioh dans le forum Langage SQL
    Réponses: 6
    Dernier message: 01/04/2004, 10h07

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