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 :

Winsock 2, HTTP (C/C++) : lenteur anormale avec recv dans une boucle


Sujet :

Réseau C

  1. #1
    Tulutu
    Invité(e)
    Par défaut Winsock 2, HTTP (C/C++) : lenteur anormale avec recv dans une boucle
    Bonjour,

    Je développe un petit programme qui a pour but de résoudre une épreuve informatique (partez pas je vous demande pas de la résoudre ), tout est bon sauf qu'une lenteur avec recv() me gêne, étant donné que le programme doit être rapide (- d'une seconde).

    J'utilise winsock pour executer ma requête HTTP, tout marche bien, sauf quand il s'agit de recevoir la réponse du serveur (il envoie une page).

    Si j'appelle recv en lui donnant un gros buffer, tout va très bien. Sauf que je cherche à faire ça plus proprement (je pense pas qu'un navigateur s'amuse à recevoir les pages dans un buffer de taille prédéfinie), et donc je place mon recv dans une boucle, pour recevoir partie par partie. Tout marche comme il faut, mais mon programme ne fait rien pendant au moins 10 secondes, alors que les données ont déjà été reçues.

    Le code responsable :
    Code C++ : 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
     
    	char * buffer = new char[BUFLEN];
     
    	do
    	{
    		iResult = recv( csocket, buffer, BUFLEN, 0 );
     
    		if( iResult > 0 )
    		{
                            //recvbuffer est de type std::string
    			recvbuffer.append( buffer, iResult );
    			ZeroMemory(buffer, BUFLEN);
    		}
    		else if( iResult == 0 )
    		{
    			std::cout << "Connection closed" << std::endl;
    		}
    		else
    		{
    			std::cout << "Error : recv(), code : " << WSAGetLastError() << std::endl;
    			shutdown( csocket, SD_BOTH );
    			closesocket( csocket );
    			WSACleanup();
    		}
    	}
    	while( iResult > 0 );
     
    	delete buffer;
     
    	std::cout << recvbuffer.c_str() << std::endl;

    Si quelqu'un voit le problème
    Merci.

    PS : j'ai cherché mais n'ai pas trouvé de topic similaire, par contre, savez-vous si le '\n' est envoyé à la toute fin de la réponse ? Je me demande si ça vient d'ici, en tout cas l'affichage se fait correctement.
    Dernière modification par Tulutu ; 05/08/2011 à 18h54.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Bonsoir,

    plusieures questions :
    - ou est-ce que ton programme bloque ?
    - qu'est-ce qui le débloque ?

    A vu de nez, je dirais que recv doit bloquer, en attendant des données sur la socket, et se débloquer quand le serveur la supprime. Si c'est cela, je te conseille d'aller chercher des informations sur la fonction select, qui te permettra de savoir s'il y a des données à lire sur la socket avant de faire un appel à une fonction bloquante.

    Par ailleurs, connaître le caractère de fin de transmission utilisé par le serveur est une excellente idée, mais je ne le connais pas. A toi de faire des tests... Mais au hasard, je testerais le '\0'.

    Enfin, si la vitesse est vraiment importante, tu devrais utiliser un tableau déclaré en static au lieu de le "mallocquer" et de le delete à chaque fois que tu appelles ta fonction. Il faudra juste que tu penses à ajouter un '\0' après chaque appel à recv.

  3. #3
    Tulutu
    Invité(e)
    Par défaut
    Alors déjà, pour tes deux questions, c'est pas trop l'heure que je mette les mains là-dedans, mais j' essaierais de te répondre plus tard.

    La fonction select m'a l'air assez pratique, j'en avais déjà entendu parler mais je n'ai pas eu l'occasion de m'en servir.
    (je parle pour mes requêtes HTTP) Si j'ai bien compris, tout l'aspect complexe de TCP (correction d'erreurs etc...) est géré au niveau du noyau, qui une fois qu'il a complètement reçu les données d'un send(), attend que le programme "au dessus" (le mien donc), demande de recevoir le tout puis lui envoie.
    Donc si select me "dit" que des données ont été reçues, c'est qu'elles sont toutes arrivées et disponibles (la page web en fait), c'est bien ça ? (d'ailleurs si c'est bien ça, ça arrange bien comme il faut quand on a besoin de debugger).

    Pour le caractère de fin de transmission : les communications sont identiques à l'échange d'une page web par HTTP de manière traditionnelle, il n'y a donc pas de caractere de fin de transmission, il me semble (je pourrais "attendre" un motif particulier qui est présent a la fin de la page, mais ce serait une solution peu pratique à réutiliser, et qui ne marche pas dans tous les cas).

    Et enfin pour la mémoire "pré-allouée" de manière statique, je serais curieux de savoir comment s'y prend un navigateur récent, pensé pour la performance. Parce qu'une page web peut faire n'importe quelle taille, jusqu'à plusieurs Mo, et donc je me demande comment ils font pour conserver les performances sans connaître la taille au préalable. Une idée ?

    En tout cas merci pour la réponse

  4. #4
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 393
    Points : 23 740
    Points
    23 740
    Par défaut
    Tout dépend de la manière dont tu as fait ta requête HTTP. En HTTP/1.1 et même en dessous avec la déclaration « Connection: Keep-Alive », le serveur web reste ouvert après l'émission de la page pendant 10 à 20 secondes pour laisser une chance au client d'émettre une nouvelle requête, plutôt que de fermer et de réouvrir une nouvelle connexion TCP à chaque fois.

  5. #5
    Membre éprouvé Avatar de orfix
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    707
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Avril 2007
    Messages : 707
    Points : 1 132
    Points
    1 132
    Par défaut
    Citation Envoyé par Tulutu Voir le message
    Donc si select me "dit" que des données ont été reçues, c'est qu'elles sont toutes arrivées et disponibles (la page web en fait), c'est bien ça ?
    Non.

    Citation Envoyé par Tulutu Voir le message
    Pour le caractère de fin de transmission : les communications sont identiques à l'échange d'une page web par HTTP de manière traditionnelle, il n'y a donc pas de caractere de fin de transmission, il me semble (je pourrais "attendre" un motif particulier qui est présent a la fin de la page, mais ce serait une solution peu pratique à réutiliser, et qui ne marche pas dans tous les cas).
    Tu devrais prendre le temps de lire le RFC2616:
    4.4 Message Length
    
    
       The transfer-length of a message is the length of the message-body as
       it appears in the message; that is, after any transfer-codings have
       been applied. When a message-body is included with a message, the
       transfer-length of that body is determined by one of the following
       (in order of precedence):
    
       1.Any response message which "MUST NOT" include a message-body (such
         as the 1xx, 204, and 304 responses and any response to a HEAD
         request) is always terminated by the first empty line after the
         header fields, regardless of the entity-header fields present in
         the message.
    
       2.If a Transfer-Encoding header field (section 14.41) is present and
         has any value other than "identity", then the transfer-length is
         defined by use of the "chunked" transfer-coding (section 3.6),
         unless the message is terminated by closing the connection.
    
       3.If a Content-Length header field (section 14.13) is present, its
         decimal value in OCTETs represents both the entity-length and the
         transfer-length. The Content-Length header field MUST NOT be sent
         if these two lengths are different (i.e., if a Transfer-Encoding
         header field is present). If a message is received with both a
         Transfer-Encoding header field and a Content-Length header field,
         the latter MUST be ignored.
    
       4.If the message uses the media type "multipart/byteranges", and the
         ransfer-length is not otherwise specified, then this self-
         elimiting media type defines the transfer-length. This media type
         UST NOT be used unless the sender knows that the recipient can arse
         it; the presence in a request of a Range header with ultiple byte-
         range specifiers from a 1.1 client implies that the lient can parse
         multipart/byteranges responses.
    
           A range header might be forwarded by a 1.0 proxy that does not
           understand multipart/byteranges; in this case the server MUST
           delimit the message using methods defined in items 1,3 or 5 of
           this section.
    
       5.By the server closing the connection. (Closing the connection
         cannot be used to indicate the end of a request body, since that
         would leave no possibility for the server to send back a response.)
    

  6. #6
    Tulutu
    Invité(e)
    Par défaut
    Bonjour,

    Tout d'abord désolé de n'avoir pas répondu plus vite, et puis merci pour toutes vos réponses.

    ssmario2 : merci beaucoup pour la citation de ce passage de la RFC qui devrait combler mes quelques incompréhensions. En fait j'étais déjà allé la consulter spontanément, sans avoir le courage de trouver les passages qui m'intéressent (c'est vachement complet quand même, mais bon tant mieux en fait).

    je ne vais pas pouvoir me pencher sur mon programme avant quelque temps, mais je passe tout de même le sujet en résolu, vos réponses suffisent à trouver la solution.

Discussions similaires

  1. [XL-2007] Problème avec If dans une boucle
    Par Runsh63 dans le forum Macros et VBA Excel
    Réponses: 6
    Dernier message: 23/06/2011, 08h48
  2. Problème avec boutons dans une boucle
    Par CHAP26 dans le forum Flash
    Réponses: 2
    Dernier message: 03/06/2008, 14h28
  3. thread avec return dans une boucle
    Par Tanebisse dans le forum Général Java
    Réponses: 19
    Dernier message: 19/05/2008, 17h42
  4. [VBA-E] pb avec offset dans une boucle
    Par davidlb dans le forum Excel
    Réponses: 4
    Dernier message: 01/04/2007, 09h15
  5. Problème avec TNMSMTP dans une boucle.
    Par Orgied dans le forum Web & réseau
    Réponses: 3
    Dernier message: 07/04/2004, 10h19

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