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

Entrée/Sortie Java Discussion :

Java, Sockets et images


Sujet :

Entrée/Sortie Java

  1. #1
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut Java, Sockets et images
    Bonjour à tous,

    Je viens à l'aide sur ce forum car je suis bloqué pour un projet d'études (réalisation d'un proxy http). Projet assez simple, interpréter la requête (GET) du client, la traiter, l'envoyer au serveur web, traiter la réponse, et l'envoyer au client. Tout fonctionne nickel à l'exception de deux "détails":

    - Accept-Encoding: gzip
    - La réception d'image
    - un soucis de performance

    Dès que "j'active" la compression je reçois un "content encoding error" dans le browser par contre si je supprime le "Accept-Encoding: gzip" ça passe sans problème...
    Je pense que ce problème est lié au second, car aucune image ne passe, dans wireshark il me dit que les données sont corrompues, mais je ne vois pas par quoi... le site que je dois pouvoir afficher est le suivant:

    http://httpd.apache.org/docs/2.2/fr/

    On peut y voir la plume en haut à gauche ainsi que la toute petite flèche vers la gauche, seul ces deux objets ne sont pas affiché...

    Par contre sur cet autre site aucun problème: http://httpwg.org/specs/ (à l'exception de l'image en haut à droite qui est en https).

    Je me demande s'il n'y aurait pas un décalage de bit quelque part qui ferait que cela est lu comme "corrompu" mais je ne vois absolument pas où, surtout que tout le reste fonctionne !!

    Le dernier point, le soucis de performance voici ce que je vois dans wireshark (par exemple)

    - (temps = 0) requête envoyée par le client;
    - (temps + 0,182026 s) requête traitée et envoyée au serveur;
    - (temps + 0,170815 s) paquet n°1 de la réponse reçu sur le serveur;
    - (temps + 0 s) paquet n°2 de la réponse reçu sur le proxy;
    - (temps + 0,000205 s) paquet n°3 de la réponse reçu sur le proxy;
    - (temps + 0,000062 s) paquet n°4 de la réponse reçu sur le proxy;
    - (temps + 0,000099 s) paquet n°5 de la réponse reçu sur le proxy (dernier paquets);
    - (temps + 29,990383 s) paquet n°1 de la réponse envoyé au client;
    - (temps + 0,000001 s) paquet n°2 de la réponse envoyé au client;
    - (temps + 0,000001 s) paquet n°3 de la réponse envoyé au client;
    - (temps + 0,000001 s) paquet n°4 de la réponse envoyé au client;
    - (temps + 0,000001 s) paquet n°5 de la réponse envoyé au client;

    On peut voir qu'entre la réception sur le serveur proxy et l'envoi vers le client il s'écoule 30sec. Est-ce que quelqu'un pourrait me dire si éventuellement il y a un timer? Je ne configure rien dans mon programme, et par défaut le timeout sur le socket est à "0" ce qui signifie "infini"...

    Est-ce que vous pouvez m'aider?

    Merci d'avance !

    Hjacquemin

  2. #2
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par hjacquemin Voir le message
    - Accept-Encoding: gzip
    - La réception d'image
    M'est d'avis (sans voir le code, difficile) que tu a traité la communication comme un flux texte, avec un StreamReader ou à tout le moins un encoder. C'est une erreur. Le HTTP, c'est du binaire, tu dois le traiter comme tel. Avec une parsing en texte, tu va détruire tout le contenu binaire (encodages asiatiques et fichiers binaires).
    Citation Envoyé par hjacquemin Voir le message
    Par contre sur cet autre site aucun problème: http://httpwg.org/specs/
    Les images de ce site sont en SVG (donc texte) ce qui me conforte dans mon idée que c'est ça ton problème.


    Citation Envoyé par hjacquemin Voir le message
    On peut voir qu'entre la réception sur le serveur proxy et l'envoi vers le client il s'écoule 30sec. Est-ce que quelqu'un pourrait me dire si éventuellement il y a un timer? Je ne configure rien dans mon programme, et par défaut le timeout sur le socket est à "0" ce qui signifie "infini"...
    Tu n'attendrais pas aussi que le serveur ferme sagement sa socket avant d'enoyer ta réponse au client par hasard? Les connections http sont persistents (+-15 à 30 secondes suivant la configuration du serveur) et c'est au client de les cloturer. Dans cette connection il peut y avoir plusieurs demandes http. https://en.wikipedia.org/wiki/HTTP_p...ction#HTTP_1.1
    Si tu attends bêtement que le serveur cloture la connection pour envoyer ta réponse au client, ça va effectivement être très lent à coup de timeouts.

  3. #3
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Bonjour Tchize,

    Citation Envoyé par tchize_ Voir le message
    M'est d'avis (sans voir le code, difficile) que tu a traité la communication comme un flux texte, avec un StreamReader ou à tout le moins un encoder. C'est une erreur. Le HTTP, c'est du binaire, tu dois le traiter comme tel. Avec une parsing en texte, tu va détruire tout le contenu binaire (encodages asiatiques et fichiers binaires).
    Merci de tout retour, j'ai la même impression que toi, mais j'avais déjà adapté mon code pour travailler en byte. A la base, je travaillais avec BufferedReader pour avoir facile à lire mon header avec la méthode readLine() en string puis j'ai changer le tout. Maintenant, j'envoie le InputSteam à ma fonction et je le copie dans un byte array pour travailler avec. Pour me faciliter la vie, je créer un BufferedReader à partir de l'array (juste pour traiter le header) et ensuite pour le Body je le prends depuis le byte array sans jamais y toucher pour ne pas corrompre les données (voici le code de ma méthode).

    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
     
    public byte[]  TraitementReponse(InputStream reponseServeur ) {
     
            final String CRLF = "\r\n";
     
            final int buffer = 33554432;
            final int maxTailleObj;
            String statusLigne = "";
            String headers = "";
            BufferedReader reponseServeurBuff = null;
            ByteArrayInputStream byteArrayInputStream = null;
            byte[] tmpArray = null;
            int count = 0;
            //byte[] body = new byte[maxTailleObj];
     
            int length = -1;
            boolean obtenirStatusLigne = false;
     
     
            try{
                // tempBuff = new InputStream(reponseServeur);
                tmpArray = org.apache.commons.io.IOUtils.toByteArray(new InputStreamReader(reponseServeur),"UTF-8");
     
                reponseServeurBuff = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(tmpArray)));
     
                //reponseServeurBuff = new BufferedReader(new InputStreamReader(tempBuff));
                String ligne = reponseServeurBuff.readLine();
     
                /**Dans la boucle ci-dessous on va lire chaque ligne de la réponse du serveur web.
                 * Tans que la taille de la ligne est différente de zéro la variable "statusLigne" récupère le contenu de cette ligne.
                 * Si le contenu de cette ligne = 0, on ajoute "\r\n" à la fin pour dire que notre requete est finie.
                 *
                 * Ensuite on test chaque ligne afin de trouvé la taille de la réponse.
                 * On récupère ensuite cette taille dans notre variable "length".
                 */
                while(ligne.length() !=0){
                    if (!obtenirStatusLigne){
                        statusLigne = ligne;
                        obtenirStatusLigne = true;
                    }
                    else{
                        headers += ligne + CRLF;
                    }
                    if (ligne.startsWith("Content-Length:") ||
                            ligne.startsWith("Content-length:")){
                        String[] tmp = ligne.split(" ");
                        length = Integer.parseInt(tmp[1]);
                    }
                    ligne = reponseServeurBuff.readLine();
                }
            }catch(IOException e) {
                System.out.println("Erreur de lecture du headers venant du serveur WEB: " + e);
            }
     
            byte[] body = new byte[length];
            String res = "";
            res = statusLigne + CRLF;
            res += headers;
            res += CRLF;
     
            int test = res.getBytes().length;
     
            byteArrayInputStream = new ByteArrayInputStream(tmpArray,test,tmpArray.length);
            // try{
            int bytesLu = 0;
            byte buf[] = new byte[buffer];
            boolean boucle = false;
     
            /**
             * La condition ci-dessous est utilisée dans le cas où il n'y aurait de "Content-length" dans la réponse.
             * On boucle ensuite dans le while jusqu'à la fermeture de la connexion.
             */
            if (length == -1){
                boucle = true;
            }
     
            /**
             * Lecture du corps de la réponse et on copie le contenu dans la variable body.
             * On s'arrête quand le nombre de bytesLu = Length ou jusque ce que la connexion se coupe.
             */
     
            while (bytesLu < length || boucle){
                int size = byteArrayInputStream.read(buf,0, buffer);
                if (size == -1) {
                    break;
                }
                /**
                 * Copie des bytes dans le body en s'assurant qu'on ne dépasse pas la taille d'objet maximum.
                 */
                for (int i =0;
                     1 < size && (i+ bytesLu) < length;
                     i++){
     
                    body[bytesLu + i] = buf[i];
                    /** trouver ce qu'il faut faire ici action avec buf[i]*/
                }
                bytesLu += size;
            }
     
            byte[] byteRequete = new byte[res.getBytes().length + body.length];
            System.arraycopy(res.getBytes(), 0, byteRequete, 0, res.getBytes().length);
            System.arraycopy(body, 0, byteRequete, res.getBytes().length, body.length);
     
            return byteRequete;
        }
    Tu n'attendrais pas aussi que le serveur ferme sagement sa socket avant d'enoyer ta réponse au client par hasard? Les connections http sont persistents (+-15 à 30 secondes suivant la configuration du serveur) et c'est au client de les cloturer. Dans cette connection il peut y avoir plusieurs demandes http. https://en.wikipedia.org/wiki/HTTP_p...ction#HTTP_1.1
    Si tu attends bêtement que le serveur cloture la connection pour envoyer ta réponse au client, ça va effectivement être très lent à coup de timeouts.
    J'avoue que pour ce point, je ne sais pas trop. Si j'analyse un peu la chose, je vois que mon serveur proxy envoi quasi immédiatement le flux vers le serveur web après réception de la requete GET. Mes sockets sont ouverts de la même manière dans les deux sens et je ne comprends pas cette différence de traitement.

    Voici les commande que j'utilise pour ouvrir et envoyer le flux sur mon socket. J'ai volontairement tronqué le code pour ne laisser que l'essentiel. S'il faut le code complet, j'ajouterai un zip.


    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
     
    Socket serveur = null;
    .
    .
    .
     
                try {
                    /**
                     * Création socket pour la commnication "Proxy --> Server Web".
                     * Création du flux de sortie nécessaire à l'établissement de la connexion.
                     */
                    serveur = new Socket(InetAddress.getByName(requeteClient.getHost()), requeteClient.getPort());
                    DataOutputStream requeteVersServeur = new DataOutputStream(serveur.getOutputStream());
     
                    /** Ajout de la requete customisée, créer dans la classe "ClientHandling" au flux de sortie.
                     * La requete est envoyer sous forme de String et convertie en Bytes via la méthode writeBytes().
                     * On force l'écriture du buffer dans le stream via l'appel de la méthode flush().
                     * Fermeture du tampon et libaration des ressources associées via la méthode close().
                     */
                    requeteVersServeur.flush();
                    requeteVersServeur.writeBytes(requeteClient.toString());
                    requeteVersServeur.flush();
     
                } catch (UnknownHostException e) {
                    System.out.println("Unknown host: " + requeteClient.getHost());
                    System.out.print(e);
                    return;
                } catch (IOException e) {
                    System.out.println("Erreur lors de l'écriture de la requête: " + e);
                    return;
                }
     
                try{
                    reponseServeur = new DataInputStream(serveur.getInputStream());
                }
                catch (IOException e){
                    System.out.println("Error lors de la lecture de la réponse du serveur: " + e);
                }
                //Ici je récupère ma réponse traitée (voir code ci-dessus);
                reponseTraitee = TraitementReponse(reponseServeur);
     
                // ici je set la réponse dans la variable d'un objet pour mon cache
                requeteClient.setReponse(reponseTraitee);
     
     
                try{
     
                // Mise à jour de mon cache
                    ProxyServeur.AddToCache(requeteClient);
     
                // Création du stream de réponse vers le client web
                    versClient = new BufferedOutputStream(client.getOutputStream());
     
                // Envoi de la réponse au client
                    versClient.write(requeteClient.getReponse());
     
                    versClient.flush();
                    versClient.close();
     
     
                    client.close();
                    serveur.close();
    .
    .
    .

    Merci d'avance pour l'aide !!

  4. #4
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par hjacquemin Voir le message
    ensuite pour le Body je le prends depuis le byte array sans jamais y toucher pour ne pas corrompre les données (voici le code de ma méthode).
    Plusieurs problèmes à ta méthode:
    Tu récupère ton byte[] en le retransformant depuis le Reader. Ce n'est pas une opération neutre. Quel est l'intérêt de prendre des bytes, d'en faire une String puis d'en refaire des bytes. Banni les Reader de ton code, ça ira mieux. Pour information, l'opération

    byte[] => String => byte[] ne retourne pas nécessairement la même séquence de byte. L'utf-8 interdit certaines séquence et le reader va les dropper, la String obtenue peut avoir été compactée car certains caractères peuvent avoir plusieurs représentations possible (genre é peut être codé comme le caractère unicode é ou comme le caractère "modificateur d'accent aigu" suivit de la lettre e). Enfin rien ne garanti que ton StreamReader va lire en utf-8.

    Ensuite, tu lit jusqu'au bout du Stream. Comme déjà mentionné dans mon post précédent, la lecture d'un réponse HTTP, ce n'est pas aussi simple.

    Pour moi tu devrais lire la réponse directement dans une array de bytes jusqu'à trouver la séquence binaire <CR><LF><CR<LF>. Tout ce qui se trouve avant fait partie des header. Tout ce qui se trouve après fait partie du content. Une fois tes header complets, tu peux les parser, les interpréter et construire ta réponse proxy, partie header. Ensuite, tu list bloc par bloc la suite de ta réponse jusque la fin du segment http et tu envoie ça au client tel quel.
    Ton code devrait donc contenir des inputStream avec ses méhode read(byte[]....) seulement.


    J'avoue que pour ce point, je ne sais pas trop. Si j'analyse un peu la chose, je vois que mon serveur proxy envoi quasi immédiatement le flux vers le serveur web après réception de la requete GET. Mes sockets sont ouverts de la même manière dans les deux sens et je ne comprends pas cette différence de traitement.

    Citation Envoyé par hjacquemin Voir le message
    Voici les commande que j'utilise pour ouvrir et envoyer le flux sur mon socket. J'ai volontairement tronqué le code pour ne laisser que l'essentiel. S'il faut le code complet, j'ajouterai un zip.
    Là aussi je vois quelques problèmes. Tu travaille avec un DataOutputStream. Tu ne devrais pas avoir besoin de cette classe. Tout comme les Reader/Writer, cette classe va te triturer tes donnée d'une manière que tu ne veux pas. Reste avec les InputStream et les OutputStream. Pareil, ta requête est une String. Pourquoi? Ton HTTP ne devrais être que des bytes, précédés des headers dont chaque ligne se fini par CRLF. L'ensemble forme un byte[]. Ton code marchera très bien pour envoyer un GET à la con vers le Serveur, mais si je fais un PUT d'un fichier binaire, tu va avoir exactement le même problème que celui que tu as à réceptionner un binaire. Oublie même l'idée d'avoir des Strings pour tes requêtes / réponse, tu ne peux pas.

    Tu dois aussi mettre en place un mécanisme plus intelligent pour gérer tes sockets. Les browsers vont tenter d'envoyer plusieurs requête sur la même socket, et toi tu ferme la socket violement. Il faut te renseigner, il y a plusieurs moyen de faire ça, mais en tant que proxy, ton code doit être capable de traiter à la fois le comportement des serveur là dessus et les exigences des clients. Tu dois traiter le fait que le serveur utilise content-lenght ou des delimiter pour marquer la fin de la réponse sans cloturer sa socket, et tu dois traiter le faire que le client veuille garder sa socket ouverte.

  5. #5
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Bonjour,

    Merci pour la réponse complète !

    Je passe en string car j'ai plus facile à interpréter mon header de la sorte, je début en Java et j'avoue que je ne vois pas commenter traiter mon flux 100 en byte. Du moins comment parser certaine partie comme juste le header pour l'analyser par la suite.

    Si je te suis, il faut uniquement utiliser des "InputStream" et "OutputStream" mais si je dois analyser mon header comment faire en byte par byte sans le convertir en string ???

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Rien ne t'empêche une fois que tu a récupérer les bytes correspondant aux headers de les transformer en String après, mais tu ne dois pas faire ça pour le reste du stream. Le plus simple pour trouver la fin des header, je pense, c'est de repérer la séquence <CR><LF><CR><LF>

  7. #7
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Salut Tchize,

    Merci pour tes infos, maintenant ça fonctionne. Je me suis amusé pour trouver le moyen de boucler et de "séparer mon header" mais j'ai bien toutes les images maintenant !

    Voici comment j'ai fait, je convertis le "InputStream" vers un byte array, ensuite je boucle avec un byte array de 4 byte pour trouver la séquence "\r\n\r\n" qui termine le header. Je copie la portion correspondant à mon, header dans un byte array (bytes bruts non convertis). Pour analyser mon header, je créer un BufferedReader qui est utilisé uniquement en lecture. Pour le body je lis juste le nombre de byte pour que tout sois ok, et je contatène mon header et mon body dans un nouveau array que je retourne.

    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
     
                byteStream = IOUtils.toByteArray(reponseServeur);
     
                /**Dans la boucle ci-dessous on va lire chaque ligne de la réponse du serveur web.
                 * Tans que la taille de la ligne est différente de zéro la variable "statusLigne" récupère le contenu de cette ligne.
                 * Si le contenu de cette ligne = 0, on ajoute "\r\n" à la fin pour dire que notre requete est finie.
                 *
                 * Ensuite on test chaque ligne afin de trouvé la taille de la réponse.
                 * On récupère ensuite cette taille dans notre variable "length".
                 */
                String parser = "\r\n\r\n";
                byte searchVal[] = parser.getBytes();;
                int longueur = byteStream.length;
     
                for(int i = 0; i <= longueur-3;i++){
                    tmpTest[0] = byteStream[i];
                    tmpTest[1] = byteStream[i+1];
                    tmpTest[2] = byteStream[i+2];
                    tmpTest[3] = byteStream[i+3];
                    if (Arrays.equals(searchVal, tmpTest))
                    {
                        headerLength += i;
                        break;
                    }
                }
                headerLength+=4;
                byteHeader = new byte[headerLength];
                System.arraycopy(byteStream, 0, byteHeader, 0, headerLength);

    Maintenant j'ai toujours un soucis de performance, et là j'avoue je n'ai aucune idée. Dans les paquets reçu du browser et du serveur web, le mode keepalive est activé chose que j'ai activée également sur les socket venant du client et ceux vers les serveurs, mais ça ne change pas grand chose.

    Par contre une fois que les données sont en cache, aucun soucis. Donc c'est bien sur la joinction entre le serveur et le client

  8. #8
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Hello,

    il est impossible de "convertir" un InputStream en byte array, sans attendre que l'InputStream soit fermé ce qui du coup est contraire à l'idée du keepalive et force à attendre que le serveur ferme sa socket puisque manifestement perdue quelque part. C'est précisément parce que c'est impossible qu'il existe d'une part des InputStream et d'autre part des byte arrays, au lieu d'avoir une seule chose qui fait les deux.

    Tu ne peux pas chercher à "lire la réponse en entier" d'abord, et à l'analyser ensuite. Tu dois l'analyser d'abord, pour savoir quand elle va se terminer.

    Normalement en lisant juste les headers qui du coup te donnent avec Content-Length la taille de ce qui reste de la réponse. Tu sais que tu as fini de lire les headers quand tu trouves une séquence \r\n\r\n, une ligne vide. Après, c'est le début de l'entité attachée, et sa taille est celle indiquée en Content-Length.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Thelvin,

    Merci pour l'info donc en gros je dois analyser mon Input Stream à la volé pour récupérer le header c'est bien ça que tu insinue et ne pas créer un byte array[] ?

    Maintenant je ne vois pas trop ce que ça change de créer le byte array directement ?

    Hjacquemin

  10. #10
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Disons que tu vas bien être obligé de buffuriser ta lecture, pour les performances et pour repérer où se trouve la fin des headers et ne pas perdre ce que tu auras lu en anticipé de ce qui se trouve après.

    Donc il va bien te falloir un byte array, mais il n'est pas censé contenir la réponse entière, entre autres parce qu'un array doit être créé avec sa taille définitive et que tu ne peux pas connaître la taille de la réponse avant d'en avoir lu une partie.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  11. #11
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Pourtant ici voici ce que je fais, je récupère mon InputStream et il est mis entièrement dans un array avant analyse...


    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
     
        public byte[]  TraitementReponse(InputStream reponseServeur ) {
     
            final String CRLF = "\r\n";
     
            final int buffer = 33554432;
     
            String statusLigne = "";
     
            String headers = "";
            BufferedReader buffedHeader = null;
            ByteArrayInputStream byteArrayInputStream = null;
            byte[] byteStream = null;
            byte[] byteHeader = null;
            byte[] tmpTest = new byte[4];
            int headerLength = 0;
            int count = 0;
     
            String dateModified = "";
            int length = -1;
            boolean obtenirStatusLigne = false;
     
     
            try{
     
                byteStream = IOUtils.toByteArray(reponseServeur);

  12. #12
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    en gros ton algo pour le moment est

    attendre la fin du Stream
    récupérer l'intégralité du stream dans un byte[]
    séparer en deux au niveau du marqueur
    traiter les header
    commencer la réponse (headers coté client)
    envoyer le contenu de la réponse


    Un code plus correct devrais suivre le schéma suivant:

    Lire les bytes disponible et le stocker dans un buffer jusqu'à atteindre le marqueur de fin des headers
    mettre le surplus déjà lu dans le buffer une buffer temporaire
    traiter les headers
    envoyer dans le contenur de la réponse le buffer temporaire déjà obtenu
    lire bloc par bloc les données restante dans l'inputStream et les envoyer dans la réponse au fur et à mesure.

  13. #13
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Un code plus correct devrais suivre le schéma suivant:

    Lire les bytes disponible et le stocker dans un buffer jusqu'à atteindre le marqueur de fin des headers
    mettre le surplus déjà lu dans le buffer une buffer temporaire
    traiter les headers
    envoyer dans le contenur de la réponse le buffer temporaire déjà obtenu
    lire bloc par bloc les données restante dans l'inputStream et les envoyer dans la réponse au fur et à mesure.

    Je comprends bien ce point de vue qui est bien plus logique que le miens, mais la seule façon que j'ai trouvé de lire la partie header est de la manière suivante:

    Je boucle avec un array temporaire de 4 bytes dans lequel j'espère trouver deux fois de suite la séquence \r\n
    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
     
                String parser = "\r\n\r\n";
                byte searchVal[] = parser.getBytes();;
                int longueur = byteStream.length;
     
                for(int i = 0; i <= longueur-3;i++){
                    tmpTest[0] = byteStream[i];
                    tmpTest[1] = byteStream[i+1];
                    tmpTest[2] = byteStream[i+2];
                    tmpTest[3] = byteStream[i+3];
                    if (Arrays.equals(searchVal, tmpTest))
                    {
                        headerLength += i;
                        break;
                    }
                }
    Maintenant le manque d'expérience se faisant sentir, je ne vois pas comment effectuer la même chose en live, car en lisant en live c'est byte par byte et je sais pas lire du byte actuel jusqu'au byte+3 pour trouver mon \r\n\r\n.

    Après ceci est fonctionne pour un serveur qui me répond avec un content-length. Si c'est des chunks, là je suis un peu perdu sur la manière de les gérer.

    Maintenant quand tu dis mettre "le surplus" dans un buffer temporaire, là tu me perds car je reçois quasi instantanément tous les bytes de la réponse du serveur.

  14. #14
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par hjacquemin Voir le message
    Maintenant le manque d'expérience se faisant sentir, je ne vois pas comment effectuer la même chose en live, car en lisant en live c'est byte par byte et je sais pas lire du byte actuel jusqu'au byte+3 pour trouver mon \r\n\r\n.
    Tu pense ton problème à l'envers. Tu peux utiliser inputStream.read(byte[]) pour lire ce qui est disponible. Ensuite tu l'accumule dans un autre buffer après avoir cherché la pattern dedans. La difficulté c'est de tenir compte de si ton nouveau buffer commence par LF et le précédent finissait par CRLFCR. Là y a du travail d'algorithmique. L'algorithme n'est pas spécialement compliqué à mon avis mais je n'ai pas trop le temps de te le coder


    Les outils dont tu as besoin pour lire ton stream sont


    int InputStream.read(buffer) qui ne remplira que ce qui est actuellement disponible et ne bloquera donc pas sauf si rien n'est disponible, auquel cas il attendra de recevoir au moin un byte
    OutputStream.write(buffer,startOffset,length) pour retransférer les données vers le destinataire.

    Pour comparer le CRLFCRLF, tu dois parcourir ton buffer de 3 à N en comparant les byte X , X-1, X-2 et X-3 avec (byte)13,(byte)10,(byte)13,(byte)10

  15. #15
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    int InputStream.read(buffer) qui ne remplira que ce qui est actuellement disponible et ne bloquera donc pas sauf si rien n'est disponible, auquel cas il attendra de recevoir au moin un byte
    OutputStream.write(buffer,startOffset,length) pour retransférer les données vers le destinataire.
    Pour le OutputStream.write, tu veux dire que je dois envoyer à la volé au client ? Ici dans mon code, je retourne le body complet une fois que je l'ai reçu...

    Pour comparer le CRLFCRLF, tu dois parcourir ton buffer de 3 à N en comparant les byte X , X-1, X-2 et X-3 avec (byte)13,(byte)10,(byte)13,(byte)10
    c'est ce que je pensais faire, sinon ceci fonctionne très bien aussi:

    String parser = "\r\n\r\n";
    byte searchVal[] = parser.getBytes();;

  16. #16
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Tu pense ton problème à l'envers. Tu peux utiliser inputStream.read(byte[]) pour lire ce qui est disponible. Ensuite tu l'accumule dans un autre buffer après avoir cherché la pattern dedans. La difficulté c'est de tenir compte de si ton nouveau buffer commence par LF et le précédent finissait par CRLFCR. Là y a du travail d'algorithmique. L'algorithme n'est pas spécialement compliqué à mon avis mais je n'ai pas trop le temps de te le coder
    je n'arrive pas du tout à travailler avec le inputStream.read(byte[])

    que je fasse ceci buffedBytes = reponseServeur.read(testBuff) pour prendre ce qu'il y a dans le InputStream à un moment T, ou que je fasse une boucle pour qu'il prenne tout ce qu'il y a jusqu'à avoir -1 rien ne passe...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
                while ((buffedBytes = reponseServeur.read()) != -1) {
                buffedBytes = reponseServeur.read(testBuff);
               }
    La seule chose qui fonctionne c'est ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    byteStream = IOUtils.toByteArray(reponseServeur);
    où mon stream complet est passé dans un byte array....

  17. #17
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par hjacquemin Voir le message
    je n'arrive pas du tout à travailler avec le inputStream.read(byte[])
    Tu peux montrer ton code? Celui que tu as posté ne faisant absolument rien du résultat, je ne sais pas comment tu en conclue qu'il ne marche pas

  18. #18
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Voilà, c'est la classe où je traite tous mes flux. Actuellement, je n'ai plus que les soucis de performances et chunks (quand j'active le Accept-Encoding: gzip, deflate)


    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
     
    import org.apache.commons.io.IOUtils;
    import java.io.*;
    import java.net.*;
    import java.lang.*;
    import java.util.Arrays;
     
    public class ProxyThreads implements Runnable {
     
        private Socket client = new Socket();
     
        /**
         * Creation du thread=:
         * @param client reception du socket client
         */
     
        public ProxyThreads(Socket client) {
            this.client = client;
        }
     
        private BufferedReader requeteBrute = null;
        private TraitementRequete requeteClient = null;
        private DataOutputStream requeteVersServeur = null;
        /** Création du stream d'entrée venant du serveur web*/
     
        InputStream reponseServeur = null;
     
        private byte[] bytesReponse = null;
        private byte[] reponseTraitee = null;
     
        BufferedOutputStream versClient = null;
     
        public void run() {
            Socket serveur = null;
     
            try {
                /** Création d'un objet de type BufferedReader nommé requeteClient.
                 *
                 * Le getter de la classe Socket est appelé pour la variable "client" (type Socket) et le contenu est
                 * passé en argument au constructeur de la classe "InputStreamReader".
                 * https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#getInputStream--
                 *
                 * "new InputStreamReader(client.getInputStream() appelle implicitement la méthode ToString de la classe "InputStreamReader".
                 *
                 * Le contenu de ce ToString est passé en argument au constructeur de la classe "BufferedReader".
                 */
     
                requeteBrute = new BufferedReader(new InputStreamReader(client.getInputStream()));
                requeteClient = Traitement(requeteBrute);
     
            } catch (IOException e) {
                System.out.println("Erreur lors de la lecture de la requête du client: " + e);
                return;
            }
            byte[] reponseFromCache = null;
            reponseFromCache = ProxyServeur.ReadFromCache(requeteClient.getUri());
     
            if(reponseFromCache != null){
     
                try{
                    //versClient.flush();
                    versClient = new BufferedOutputStream(client.getOutputStream());
                    versClient.write(reponseFromCache);
     
                    versClient.flush();
                    versClient.close();
     
     
                    client.close();
                    serveur.close();
     
                }catch(IOException e){
                    System.out.println("Error lors de l'écriture de la réponse au client: " + e);
                }
            }
     
            else{
                try {
                    /**
                     * Création socket pour la commnication "Proxy --> Server Web".
                     * Création du flux de sortie nécessaire à l'établissement de la connexion.
                     */
                    serveur = new Socket(InetAddress.getByName(requeteClient.getHost()), requeteClient.getPort());
                    serveur.setKeepAlive(true);
                    DataOutputStream requeteVersServeur = new DataOutputStream(serveur.getOutputStream());
     
                    /** Ajout de la requete customisée, créer dans la classe "ClientHandling" au flux de sortie.
                     * La requete est envoyer sous forme de String et convertie en Bytes via la méthode writeBytes().
                     * On force l'écriture du buffer dans le stream via l'appel de la méthode flush().
                     * Fermeture du tampon et libaration des ressources associées via la méthode close().
                     */
                    requeteVersServeur.flush();
                    requeteVersServeur.writeBytes(requeteClient.toString());
                    requeteVersServeur.flush();
     
                } catch (UnknownHostException e) {
                    System.out.println("Unknown host: " + requeteClient.getHost());
                    System.out.print(e);
                    return;
                } catch (IOException e) {
                    System.out.println("Erreur lors de l'écriture de la requête: " + e);
                    return;
                }
     
                try{
                    reponseServeur = serveur.getInputStream();
                    reponseTraitee = TraitementReponse(reponseServeur);
                    requeteClient.setReponse(reponseTraitee);
                }
                catch (IOException e){
                    System.out.println("Error lors de la lecture de la réponse du serveur: " + e);
                }
     
     
                try{
     
                    ProxyServeur.AddToCache(requeteClient);
                    //versClient.flush();
                    versClient = new BufferedOutputStream(client.getOutputStream());
                    versClient.write(requeteClient.getReponse());
     
                    versClient.flush();
                    versClient.close();
     
     
                    client.close();
                    serveur.close();
                    /**Objet en cache*/
                    /**}
                     else{
                     BufferedOutputStream versClient = new BufferedOutputStream(client.getOutputStream());
                     versClient.write(cache);
                     versClient.flush();
                     versClient.close();
     
     
                     client.close();
                     serveur.close();
                     }*/
     
                }catch (IOException e){
                    System.out.println("Error lors de l'écriture de la réponse au client: " + e);
                }
            }
        }
     
     
        public TraitementRequete Traitement(BufferedReader requeteBrute) {
            /** Création de la variable de retour chariot et le port http par defaut pour les requêtes vers les serveurs web */
            final String CRLF = "\r\n";
            final int PortDefaut = 80;
     
            /** Création des variables, issue de la requêtes HTML, utilisées pour appeler le constructeur de la classe ClientHandling*/
            String method = "";
            String uri = "";
            String version = "";
            String headers = "";
            String host = "";
            int port = 0;
     
            /** Création de la variable qui recevra la 1ière ligne de la requête client*/
            String firstLine = "";
     
            try {
                /** Récupération de la 1ière ligne de la requête */
                firstLine = requeteBrute.readLine();
            } catch (IOException e) {
                /** Erreur générée si la requête ne peut être lue */
                System.out.println("Erreur lors de la lecture de la requete: " + e);
            }
     
            /** Création d'une variable temporaire "tmp" qui reçoit les différentes information de la première ligne de la requête*/
     
            String[] tmp = firstLine.split(" ");
            method = tmp[0];
            uri = tmp[1];
            version = tmp[2];
     
            /** Test afin de déterminer si la requête est bien un "Get";
             * Si pas, une erreur est affichée en console
             * */
     
            if (method.equals("GET")) {
     
                /** second test afin de déterminer si la version est bien de type HTTP/1.0 ou HTTP/1.1
                 * Si pas, une erreur est affichée en console.
                 * */
     
                if (version.equals("HTTP/1.0") || version.equals("HTTP/1.1")) {
                    //System.out.println("OK version = " + version);
                    try {
     
                        /** Après avoir récupérer le stream entrant, on tente de le lire pour récupérer le Header, le formater pour l'utiliser par la suite.
                         * La variable "line"(String) reçoit la première ligne contenue dans l'objet "from" reçu en argument dans le constructeur.
                         * Chaque ligne est ajouter à la variable "headers" et une fin de ligne (CRLF) est ajoutée en fin de ligne.
                         * On reproduit la boucle jusqu'à ce qu'il n'y ait plus de ligne dans la variable "from".
                         *
                         * Le reste effectue quelques opération afin de formater le pquet au mieux pour avoir un résultat similaire à:
                         *
                         * Host: www.perdu.com
                         * Proxy-Connection: keep-alive
                         * Cache-Control: max-age=0
                         * User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
                         * Upgrade-Insecure-Requests: 1
                         * Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,* /*;q=0.8   ----> la ligne a été volontairement tronquée par un " " pour éviter le symbole de fin de commentaire.
                         * Accept-Encoding: gzip, deflate
                         * Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
                         *
                         */
                        String ligne = requeteBrute.readLine();
                        //headers += ligne + CRLF;
     
                        while (ligne.length() != 0) {
                            // ligne = requeteBrute.readLine();
     
                            // System.out.println("headers = " + headers);
                            if (ligne.startsWith("Host:")) {
                                tmp = ligne.split(" ");
                                if (tmp[1].indexOf(':') > 0) {
                                    String[] tmp2 = tmp[1].split(":");
                                    host = tmp2[0];
                                    port = Integer.parseInt(tmp2[1]);
                                } else {
                                    host = tmp[1];
                                    port = PortDefaut;
                                }
                            }
                            if (ligne.startsWith("Accept-Encoding:")||
                                    ligne.startsWith("Accept-encoding:")){
                               // headers += "Accept-Encoding: gzip" + CRLF;
                            }
                            else{
                                headers += ligne + CRLF;
                            }
                            ligne = requeteBrute.readLine();
                        }
                    } catch (IOException e) {
                        System.out.println("Erreur de lecture du socket: " + e);
                    }
                    //System.out.println("L'hôte à contacter est " + host + " sur le port " + port);
                } else {
                    try{
                        System.out.println("Version " + version + " n'est pas supportée.");
                        client.close();
                    }catch(IOException e){
                        System.out.println("Error lors de la fermeture du socket client: " + e);
                    }
     
                }
            } else {
                try{
                    client.close();
                    System.out.println("Seules les requêtes \"GET\" sont supportées.");
                }catch(IOException e){
                    System.out.println("Error lors de la fermeture du socket client: " + e);
                }
            }
     
            TraitementRequete requeteTraitee = new TraitementRequete(method, uri, version, headers, host, port);
            return requeteTraitee;
        }
     
     
        public byte[]  TraitementReponse(InputStream reponseServeur ) {
     
            final String CRLF = "\r\n";
     
            final int buffer = 33554432;
     
            String statusLigne = "";
     
            String headers = "";
            BufferedReader buffedHeader = null;
            ByteArrayInputStream byteArrayInputStream = null;
            byte[] byteStream = null;
            byte[] byteHeader = null;
            byte[] tmpTest = new byte[4];
            int headerLength = 0;
            int count = 0;
     
            String dateModified = "";
            int length = -1;
            boolean obtenirStatusLigne = false;
     
     
            try{
     
                byteStream = IOUtils.toByteArray(reponseServeur);
     
                /**Dans la boucle ci-dessous on va lire chaque ligne de la réponse du serveur web.
                 * Tans que la taille de la ligne est différente de zéro la variable "statusLigne" récupère le contenu de cette ligne.
                 * Si le contenu de cette ligne = 0, on ajoute "\r\n" à la fin pour dire que notre requete est finie.
                 *
                 * Ensuite on test chaque ligne afin de trouvé la taille de la réponse.
                 * On récupère ensuite cette taille dans notre variable "length".
                 */
                String parser = "\r\n\r\n";
                byte searchVal[] = parser.getBytes();;
                int longueur = byteStream.length;
     
                for(int i = 0; i <= longueur-3;i++){
                    tmpTest[0] = byteStream[i];
                    tmpTest[1] = byteStream[i+1];
                    tmpTest[2] = byteStream[i+2];
                    tmpTest[3] = byteStream[i+3];
                    if (Arrays.equals(searchVal, tmpTest))
                    {
                        headerLength += i;
                        break;
                    }
                }
                headerLength+=4;
                byteHeader = new byte[headerLength];
                System.arraycopy(byteStream, 0, byteHeader, 0, headerLength);
     
                buffedHeader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(byteHeader)));
     
                //reponseServeurBuff = new BufferedReader(new InputStreamReader(tempBuff));
                String ligne = buffedHeader.readLine();
     
     
                while(ligne.length() !=0){
                    if (!obtenirStatusLigne){
                        statusLigne = ligne;
                        obtenirStatusLigne = true;
                    }
                    else{
                        headers += ligne + CRLF;
                    }
     
                    if(ligne.startsWith("Last-Modified:")||
                            ligne.startsWith("Last-modified:")){
                        String[] tmp1 = ligne.split(": ");
                        dateModified = tmp1[1];
                    }
                    if (ligne.startsWith("Content-Length:") ||
                            ligne.startsWith("Content-length:")){
                        String[] tmp2 = ligne.split(" ");
                        length = Integer.parseInt(tmp2[1]);
                    }
     
                    ligne = buffedHeader.readLine();
                }
            }catch(IOException e) {
                System.out.println("Erreur de lecture du headers venant du serveur WEB: " + e);
            }
     
            requeteClient.setDateModified(dateModified);
     
            byte[] body = new byte[length];
     
            byteArrayInputStream = new ByteArrayInputStream(byteStream,headerLength,byteStream.length);
     
            int bytesLu = 0;
            byte buf[] = new byte[buffer];
            boolean boucle = false;
     
            /**
             * La condition ci-dessous est utilisée dans le cas où il n'y aurait de "Content-length" dans la réponse.
             * On boucle ensuite dans le while jusqu'à la fermeture de la connexion.
             */
            if (length == -1){
                boucle = true;
            }
     
            /**
             * Lecture du corps de la réponse et on copie le contenu dans la variable body.
             * On s'arrête quand le nombre de bytesLu = Length ou jusque ce que la connexion se coupe.
             */
     
            while (bytesLu < length || boucle){
                int size = byteArrayInputStream.read(buf,0, buffer);
                if (size == -1) {
                    break;
                }
                /**
                 * Copie des bytes dans le body en s'assurant qu'on ne dépasse pas la taille d'objet maximum.
                 */
                for (int i =0;
                     1 < size && (i+ bytesLu) < length;
                     i++){
     
                    body[bytesLu + i] = buf[i];
                    /** trouver ce qu'il faut faire ici action avec buf[i]*/
                }
                bytesLu += size;
            }
     
            byte[] byteRequete = new byte[byteHeader.length + body.length];
            System.arraycopy(byteHeader, 0, byteRequete, 0, byteHeader.length);
            System.arraycopy(body, 0, byteRequete, byteHeader.length, body.length);
     
            return byteRequete;
        }
     
    }

  19. #19
    Candidat au Club
    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Septembre 2017
    Messages
    15
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Septembre 2017
    Messages : 15
    Points : 3
    Points
    3
    Par défaut
    Salut à tous,

    Est-ce que quelqu'un peut me faire un retour sur ce qui pourrait être les soucis de performances dans mon code ??

    Entre temps, j'ai pris en charge le traitement des chunks, ça marche sur firefox, mais pas sur chrome, je reçois un "ERR_INVALID_CHUNKED_ENCODING"

    Pour mes chunks je procèdes de la manière suivante:

    - Le lis le header et je regarde si c'est du chunk
    - Si c'est le cas, j'analyse mon byte stream pour trouver le \r\n TAILLE \r\n;
    - Ensuite je scanne le stream et compte les bytes;
    - Je reconstruit mon paquet

    J'ai vraiment besoin d'aide ou de pistes à creuser pour ce soucis de perfs, je dois remettre mon travail dans 2 jours

    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
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    import org.apache.commons.io.IOUtils;
    import java.io.*;
    import java.net.*;
    import java.lang.*;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Arrays;
    import java.util.*;
     
    /**Ceci est le coeur de notre programme. Cette classe permet le traitement de la
     * requete du client, l'envoi vers le serveur Web, le traitement de la reponse,
     * et l'envoi de cette derniere vers le client.
     *
     * Cette classe est diviee en quatre methode dont trois principales:
     *
     * <pre>
     *    - La methode run(), dans laquelle chaque thread sera traite;
     *    - La methode Traitement() utilisee pour le traitement de la requete venant du client;
     *    - La methode TraitementReponse() analyse la réponse du serveur et format la réponse pour le client;
     *    - La methode UpdateDispo() qui s'occupe quant a elle d'analyser la réponse HEAD pour la validité du cache.
     * </pre>
     * @author  Herve Jacquemin et Arnaud Vaneukem
     * @version 1.0
     * @since   2017-12-03
     */
     
    public class ProxyThreads implements Runnable {
     
        private Socket client = new Socket();
     
        /** Constructeur de la classe ProxyThreads().
         * On reçoit le socket en argument et on s'occupe de creer
         * le thread qui sera associe au socket.
         *
         * @param client reception du socket client
         */
        public ProxyThreads(Socket client) {
            this.client = client;
        }
     
        private BufferedReader requeteBrute = null;
        private TraitementRequete requeteClient = null;
        private DataOutputStream versServeur = null;
        private BufferedReader headReponse = null;
       //private DataOutputStream requeteVersServeur = null;
        private SimpleDateFormat dateFormatter = null;
        private Date dateFromCache = null;
        private Date dateUpdated = null;
        /** Création du stream d'entrée venant du serveur web*/
        private Socket serveur = null;
        private InputStream reponseServeur = null;
     
        private byte[] bytesReponse = null;
        private byte[] reponseTraitee = null;
     
        private BufferedOutputStream versClient = null;
        private String dateUpdate = null;
     
     
        public void run() {
     
     
            try {
                /** Création d'un objet de type BufferedReader nommé requeteClient.
                 *
                 * Le getter de la classe Socket est appelé pour la variable "client" (type Socket) et le contenu est
                 * passé en argument au constructeur de la classe "InputStreamReader".
                 * https://docs.oracle.com/javase/8/docs/api/java/net/Socket.html#getInputStream--
                 *
                 * "new InputStreamReader(client.getInputStream() appelle implicitement la méthode ToString de la classe "InputStreamReader".
                 *
                 * Le contenu de ce ToString est passé en argument au constructeur de la classe "BufferedReader".
                 */
     
                requeteBrute = new BufferedReader(new InputStreamReader(client.getInputStream()));
                requeteClient = Traitement(requeteBrute);
     
            } catch (IOException e) {
                System.out.println("Erreur lors de la lecture de la requête du client: " + e);
                return;
            }
            TraitementRequete reponseFromCache = null;
            reponseFromCache = ProxyServeur.ReadFromCache(requeteClient.getUri());
     
            if(reponseFromCache != null){
     
                try{
                    serveur = new Socket(InetAddress.getByName(requeteClient.getHost()), requeteClient.getPort());
                    versServeur = new DataOutputStream(serveur.getOutputStream());
     
                /** Ajout de la requete customisée, créer dans la classe "ClientHandling" au flux de sortie.
                 * La requete est envoyer sous forme de String et convertie en Bytes via la méthode writeBytes().
                 * On force l'écriture du buffer dans le stream via l'appel de la méthode flush().
                 * Fermeture du tampon et libaration des ressources associées via la méthode close().
                 */
                    versServeur.flush       ();
                    versServeur.writeBytes(requeteClient.HeadString());
                    versServeur.flush();
     
     
                    headReponse = new BufferedReader(new InputStreamReader(serveur.getInputStream()));
     
                    dateUpdate = UpdateDispo(headReponse);
                    dateFormatter = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z",Locale.US);
     
                    try {
                        dateUpdated = dateFormatter.parse(dateUpdate);
                        dateFromCache = dateFormatter.parse(reponseFromCache.getDateModified());
                    }catch(java.text.ParseException e){
                        System.out.println(e);
                    }
     
                    if(dateFromCache.equals(dateUpdated) || reponseFromCache.getDateModified() == null){
                        System.out.println("les dates sont égales");
                        versClient = new BufferedOutputStream(client.getOutputStream());
                        versClient.write(reponseFromCache.getReponse());
     
                        versClient.flush();
                        versClient.close();
                        client.close();
                        serveur.close();
                    }
                    else{
                        ProxyServeur.DeleteFromCache(requeteClient.getUri());
                    }
                }catch(IOException e){
                    System.out.println("Error lors de l'écriture de la réponse au client: " + e);
                }
            }
            else{
                try {
                    /**
                     * Création socket pour la commnication "Proxy --> Server Web".
                     * Création du flux de sortie nécessaire à l'établissement de la connexion.
                     */
                    serveur = new Socket(InetAddress.getByName(requeteClient.getHost()), requeteClient.getPort());
                     versServeur = new DataOutputStream(serveur.getOutputStream());
     
                    /** Ajout de la requete customisée, créer dans la classe "ClientHandling" au flux de sortie.
                     * La requete est envoyer sous forme de String et convertie en Bytes via la méthode writeBytes().
                     * On force l'écriture du buffer dans le stream via l'appel de la méthode flush().
                     * Fermeture du tampon et libaration des ressources associées via la méthode close().
                     */
                    //requeteVersServeur.flush();
                    //requeteVersServeur.writeBytes(requeteClient.toString());
                    //requeteVersServeur.flush();
                    //versServeur.flush();
                    versServeur.writeBytes(requeteClient.toString());
                    versServeur.flush();
     
                } catch (UnknownHostException e) {
                    System.out.println("Unknown host: " + requeteClient.getHost());
                    System.out.print(e);
                    return;
                } catch (IOException e) {
                    System.out.println("Erreur lors de l'écriture de la requête: " + e);
                    return;
                }
     
                try{
                    reponseServeur = serveur.getInputStream();
                    reponseTraitee = TraitementReponse(reponseServeur);
                    requeteClient.setReponse(reponseTraitee);
                }
                catch (IOException e){
                    System.out.println("Error lors de la lecture de la réponse du serveur: " + e);
                }
     
     
                try{
     
                    ProxyServeur.AddToCache(requeteClient);
                    //versClient.flush();
                    versClient = new BufferedOutputStream(client.getOutputStream());
                    versClient.write(requeteClient.getReponse());
     
                    versClient.flush();
                    versClient.close();
     
     
                    client.close();
                    serveur.close();
                    /**Objet en cache*/
                    /**}
                     else{
                     BufferedOutputStream versClient = new BufferedOutputStream(client.getOutputStream());
                     versClient.write(cache);
                     versClient.flush();
                     versClient.close();
     
     
                     client.close();
                     serveur.close();
                     }*/
     
                }catch (IOException e){
                    System.out.println("Error lors de l'écriture de la réponse au client: " + e);
                }
            }
        }
     
     
        public TraitementRequete Traitement(BufferedReader requeteBrute) {
            /** Création de la variable de retour chariot et le port http par defaut pour les requêtes vers les serveurs web */
            final String CRLF = "\r\n";
            final int PortDefaut = 80;
     
            /** Création des variables, issue de la requêtes HTML, utilisées pour appeler le constructeur de la classe ClientHandling*/
            String method = "";
            String uri = "";
            String version = "";
            String headers = "";
            String host = "";
            int port = 0;
     
            /** Création de la variable qui recevra la 1ière ligne de la requête client*/
            String firstLine = "";
     
            try {
                /** Récupération de la 1ière ligne de la requête */
                firstLine = requeteBrute.readLine();
            } catch (IOException e) {
                /** Erreur générée si la requête ne peut être lue */
                System.out.println("Erreur lors de la lecture de la requete: " + e);
            }
     
            /** Création d'une variable temporaire "tmp" qui reçoit les différentes information de la première ligne de la requête*/
     
            String[] tmp = firstLine.split(" ");
            method = tmp[0];
            uri = tmp[1];
            version = tmp[2];
     
            /** Test afin de déterminer si la requête est bien un "Get";
             * Si pas, une erreur est affichée en console
             * */
     
            if (method.equals("GET")) {
     
                /** second test afin de déterminer si la version est bien de type HTTP/1.0 ou HTTP/1.1
                 * Si pas, une erreur est affichée en console.
                 * */
     
                if (version.equals("HTTP/1.0") || version.equals("HTTP/1.1")) {
                    //System.out.println("OK version = " + version);
                    try {
     
                        /** Après avoir récupérer le stream entrant, on tente de le lire pour récupérer le Header, le formater pour l'utiliser par la suite.
                         * La variable "line"(String) reçoit la première ligne contenue dans l'objet "from" reçu en argument dans le constructeur.
                         * Chaque ligne est ajouter à la variable "headers" et une fin de ligne (CRLF) est ajoutée en fin de ligne.
                         * On reproduit la boucle jusqu'à ce qu'il n'y ait plus de ligne dans la variable "from".
                         *
                         * Le reste effectue quelques opération afin de formater le pquet au mieux pour avoir un résultat similaire à:
                         *
                         * Host: www.perdu.com
                         * Proxy-Connection: keep-alive
                         * Cache-Control: max-age=0
                         * User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
                         * Upgrade-Insecure-Requests: 1
                         * Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,* /*;q=0.8   ----> la ligne a été volontairement tronquée par un " " pour éviter le symbole de fin de commentaire.
                         * Accept-Encoding: gzip, deflate
                         * Accept-Language: fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
                         *
                         */
                        String ligne = requeteBrute.readLine();
                        //headers += ligne + CRLF;
     
                        while (ligne.length() != 0) {
                            // ligne = requeteBrute.readLine();
     
                            // System.out.println("headers = " + headers);
                            if (ligne.startsWith("Host:")) {
                                tmp = ligne.split(" ");
                                if (tmp[1].indexOf(':') > 0) {
                                    String[] tmp2 = tmp[1].split(":");
                                    host = tmp2[0];
                                    port = Integer.parseInt(tmp2[1]);
                                } else {
                                    host = tmp[1];
                                    port = PortDefaut;
                                }
                            }
                            if (ligne.startsWith("Accept-Encoding:")||
                                    ligne.startsWith("Accept-encoding:")){
                               headers += "Accept-Encoding: gzip" + CRLF;
                            }
                            else{
                                headers += ligne + CRLF;
                            }
                            ligne = requeteBrute.readLine();
                        }
                    } catch (IOException e) {
                        System.out.println("Erreur de lecture du socket: " + e);
                    }
                    //System.out.println("L'hôte à contacter est " + host + " sur le port " + port);
                } else {
                    try{
                        System.out.println("Version " + version + " n'est pas supportée.");
                        client.close();
                    }catch(IOException e){
                        System.out.println("Error lors de la fermeture du socket client: " + e);
                    }
     
                }
            } else {
                try{
                    client.close();
                    System.out.println("Seules les requêtes \"GET\" sont supportées.");
                }catch(IOException e){
                    System.out.println("Error lors de la fermeture du socket client: " + e);
                }
            }
     
            TraitementRequete requeteTraitee = new TraitementRequete(method, uri, version, headers, host, port);
            return requeteTraitee;
        }
     
     
        public byte[]  TraitementReponse(InputStream reponseServeur ) {
     
            final String CRLF = "\r\n";
     
            final int buffer = 33554432;
     
            String statusLigne = "";
     
            String headers = "";
            BufferedReader buffedHeader = null;
            BufferedReader buffedChunk = null;
            ByteArrayInputStream byteArrayInputStream = null;
            byte[] byteStream = null;
            byte[] byteHeader = null;
            byte[] tmpTest = new byte[4];
            byte[] tmpTest2 = new byte[2];
            byte[] body = null;
            String finChunk = "\r\r0\r\n";
            byte[] finChunkBytes = finChunk.getBytes();
            int longueur = 0;
            int headerLength = 0;
            int chunkLength = 0;
            int tailleByteChunk = 0;
            byte[] byteChunk = null;
            boolean chunk = false;
            int count = 0;
     
     
     
            String dateModified = "";
            int length = -1;
            boolean obtenirStatusLigne = false;
     
     
            try{
     
                byteStream = IOUtils.toByteArray(reponseServeur);
     
                /**Dans la boucle ci-dessous on va lire chaque ligne de la réponse du serveur web.
                 * Tans que la taille de la ligne est différente de zéro la variable "statusLigne" récupère le contenu de cette ligne.
                 * Si le contenu de cette ligne = 0, on ajoute "\r\n" à la fin pour dire que notre requete est finie.
                 *
                 * Ensuite on test chaque ligne afin de trouvé la taille de la réponse.
                 * On récupère ensuite cette taille dans notre variable "length".
                 */
                longueur = byteStream.length;
                String parser = "\r\n\r\n";
                byte searchVal[] = parser.getBytes();
     
                for(int i = 0; i <= longueur-3;i++){
                    tmpTest[0] = byteStream[i];
                    tmpTest[1] = byteStream[i+1];
                    tmpTest[2] = byteStream[i+2];
                    tmpTest[3] = byteStream[i+3];
                    if (Arrays.equals(searchVal, tmpTest))
                    {
                        headerLength += i;
                        break;
                    }
                }
                headerLength+=4;
                byteHeader = new byte[headerLength];
                System.arraycopy(byteStream, 0, byteHeader, 0, headerLength);
     
                buffedHeader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(byteHeader)));
     
                //reponseServeurBuff = new BufferedReader(new InputStreamReader(tempBuff));
                String ligne = buffedHeader.readLine();
     
     
                while(ligne.length() !=0){
                    if (!obtenirStatusLigne){
                        statusLigne = ligne;
                        obtenirStatusLigne = true;
                    }
                    else{
                        headers += ligne + CRLF;
                    }
     
                    if(ligne.startsWith("Last-Modified:")||
                            ligne.startsWith("Last-modified:")){
                        String[] tmp1 = ligne.split(": ");
                        dateModified = tmp1[1];
                    }
                    if (ligne.startsWith("Content-Length:") ||
                            ligne.startsWith("Content-length:")){
                        String[] tmp2 = ligne.split(" ");
                        length = Integer.parseInt(tmp2[1]);
                    }
     
                    if (ligne.startsWith("Transfer-Encoding: chunked") ||
                            ligne.startsWith("Transfer-encoding: chunked")){
                        String[] tmp2 = ligne.split(" ");
                        chunk = true;
                    }
     
                    ligne = buffedHeader.readLine();
                }
            }catch(IOException e) {
                System.out.println("Erreur de lecture du headers venant du serveur WEB: " + e);
            }
     
            requeteClient.setDateModified(dateModified);
     
            try{
                if(chunk){
                    String parser = "\r\n";
                    byte searchVal[] = parser.getBytes();;
                    for(int i = headerLength; i <= longueur-3;i++){
                        tmpTest2[0] = byteStream[i];
                        tmpTest2[1] = byteStream[i+1];
                        //tmpTest[2] = byteStream[i+2];
                        //tmpTest[3] = byteStream[i+3];
                        if (Arrays.equals(searchVal, tmpTest2))
                        {
                            chunkLength += i;
                            break;
                        }
                    }
     
                    chunkLength+=2;
                    byteChunk = new byte[chunkLength-headerLength];
                    System.arraycopy(byteStream, headerLength, byteChunk, 0, chunkLength-headerLength);
     
                    buffedChunk = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(byteChunk)));
     
                    //reponseServeurBuff = new BufferedReader(new InputStreamReader(tempBuff));
     
                    tailleByteChunk = Integer.parseInt(buffedChunk.readLine(),16);
     
                    //body = new byte[tailleByteChunk];
                }
            }catch(IOException e) {}
     
     
            int bodyLength = 0;
     
            if(chunk){
                bodyLength = tailleByteChunk;
                headerLength +=chunkLength-headerLength;
            }else{
                bodyLength = length;
            }
     
            body = new byte[bodyLength];
     
                byteArrayInputStream = new ByteArrayInputStream(byteStream,headerLength,byteStream.length);
     
                int bytesLu = 0;
                byte buf[] = new byte[buffer];
                boolean boucle = false;
     
                /**La condition ci-dessous est utilisée dans le cas où il n'y aurait de "Content-length" dans la réponse.
                 * On boucle ensuite dans le while jusqu'à la fermeture de la connexion.
                 */
                if (bodyLength == -1){
                    boucle = true;
                }
     
                /**Lecture du corps de la réponse et on copie le contenu dans la variable body.
                 * On s'arrête quand le nombre de bytesLu = Length ou jusque ce que la connexion se coupe.
                 */
     
                while (bytesLu < bodyLength || boucle){
                    int size = byteArrayInputStream.read(buf,0, buffer);
                    if (size == -1) {
                        break;
                    }
                /**
                 * Copie des bytes dans le body en s'assurant qu'on ne dépasse pas la taille d'objet maximum.
                 */
                for (int i =0;
                     1 < size && (i+ bytesLu) < bodyLength;
                     i++){
     
                    body[bytesLu + i] = buf[i];
                    /** trouver ce qu'il faut faire ici action avec buf[i]*/
                }
                bytesLu += size;
            }
     
            byte[] byteRequete = new byte[byteStream.length];
     
     
            if (chunk){
                System.arraycopy(byteHeader, 0, byteRequete, 0, byteHeader.length);
                System.arraycopy(byteChunk, 0, byteRequete, byteHeader.length,byteChunk.length);
                System.arraycopy(body, 0, byteRequete, byteHeader.length+byteChunk.length, body.length);
                System.arraycopy(finChunkBytes, 0, byteRequete,byteHeader.length+byteChunk.length+body.length,finChunkBytes.length);
     
            }else{
                System.arraycopy(byteHeader, 0, byteRequete, 0, byteHeader.length);
                System.arraycopy(body, 0, byteRequete, byteHeader.length, body.length);
            }
     
     
            return byteRequete;
        }
     
     
     
     
     
        public String UpdateDispo(BufferedReader head) {
     
     
            String timeStampUpdated = null;
     
            try{
     
                String ligne = head.readLine();
     
                while (ligne.length() != 0) {
     
                    if (ligne.startsWith("Last-Modified:") ||
                            ligne.startsWith("Last-modified:")) {
                        String[] tmp1 = ligne.split(": ");
                        timeStampUpdated = tmp1[1];
                        break;
                    }
                    ligne = head.readLine();
                }
     
            }catch(IOException e){
                System.out.println("Erreur lors de l'écriture du paquet HEAD" + e);
            }
     
            return timeStampUpdated;
        }
    }

  20. #20
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par hjacquemin Voir le message
    Est-ce que quelqu'un peut me faire un retour sur ce qui pourrait être les soucis de performances dans mon code ??
    Je l'ai déjà fait, tu ne peux pas convertir un InputStream en byte array, cela force à attendre le timeout, donc performances exécrables.

    Tu dois lire le flux au fur et à mesure, pas en une fois. C'est comme ça tu sais, tu n'y couperas pas.

    Tu dis que tu n'y arrives pas mais tu ne montres pas le code quand on te le demande. Tu ne peux pas être si pressé que ça si tu fais volontairement durer.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. Java : socket, octects perdus
    Par thebloodyman dans le forum Entrée/Sortie
    Réponses: 2
    Dernier message: 03/09/2007, 09h39
  2. [JAVA] Redimension d'image
    Par elanari dans le forum 2D
    Réponses: 10
    Dernier message: 08/03/2007, 23h49
  3. Java et traitement image
    Par martini37 dans le forum 2D
    Réponses: 13
    Dernier message: 14/02/2007, 12h48
  4. Débutant Java, Sockets et observers
    Par nouknouk dans le forum Entrée/Sortie
    Réponses: 8
    Dernier message: 19/12/2006, 14h01
  5. [Java][Socket] Pas de lecture de flux
    Par mavina dans le forum Entrée/Sortie
    Réponses: 7
    Dernier message: 20/10/2006, 19h02

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