Publié le 23/07/2013
Auteur Fobec
Réseaux sociaux
0 partages
0 tweets
0 plus
0 commentaires

Communiquer directement avec un socket

Tous les échanges sur un réseau passe par une connexion à un socket. Par exemple, le chargement d'une page internet nécessite l'ouverture d'un socket, l'envoi de requête puis la réception du code HTML.
La plupart de ces opérations sont invisibles pour l'internautes, voire même pour le développeur. Par contre il peut être utile de savoir ce qui se cache derrière les communications entre un client et un serveur.

Envoi et reception de données avec la Class HttpRawSocket

Contrairement à HttpURLConnection, la class est un wrapper minimaliste de l'objet JAVA socket. Les fonctions implémentées servent à couvrir les requêtes courantes:
- connect(): se connecter puis receptionner la réponse,
- setUserAgent(): fixer le UserAgent, car certains serveurs bloquent s'il n'est pas défini,
- setEncoding(): demander la compression gzip de la page,
- getHeader(): retourne l'entete de la page HTML,
- getHtml(): retourne le code source de la page.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
 
/**
 * Communiquer directement avec un socket
 * @author Fobec 2013
 * @see http://www.fobec.com/java/1130/communiquer-directement-avec-socket.html
 */
public class HttpRawSocket {
 
    private String request = ""; //commande envoye
    private String header=""; //reponse header
    private String html=""; //reponse html
    private String ua = null; //user agent
    private boolean gzip=false; //compression demande
 
    /**
     * Ouvrir un socket et envoyer une commande
     * @param aURL
     * @throws MalformedURLException
     * @throws IOException 
     */
    public void connect(String aURL) throws MalformedURLException, IOException {
        Socket socket = new Socket();
        URL url = new URL(aURL);
        socket.connect(new InetSocketAddress(url.getHost(), 80));
        try {
            InputStreamReader inputreader=new InputStreamReader(socket.getInputStream());
            BufferedReader reader = new BufferedReader(inputreader);
            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            //envoyer la requete
            this.request=this.buildCommand(url);
            writer.println(this.request);
            //receptionner la réponse
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = reader.readLine()) != null) {
                sb.append(line).append(System.getProperty("line.separator"));
            }
            //Séparer le header du code html
            String response = sb.toString();
            String tag=System.getProperty("line.separator")+System.getProperty("line.separator");
            int idx=response.indexOf(tag);       
            this.header = response.substring(0,idx);
            this.html = response.substring(idx+1);
        } finally {
            socket.close();
        }
    }
 
    /**
     * Fixer le UserAgent
     * @param useragent 
     */
    public void setUserAgent(String useragent) {
        this.ua = useragent;
    }
    //Fixer la compression
    public void setEncoding(boolean acceptGzip) {
        this.gzip = acceptGzip;
    }
    //Retourner la requete envoyé au serveur
    public String getRequest() {
        return this.request;
    }
    //Retourner le header de la réponse
    public String getHeader() {
        return this.header;
    }
    //retourner le code html
    public String getHtml() {
        return this.html;
    }
    /**
     * Assembler la requete à envoyer au serveur
     * @param url
     * @return 
     */
    private String buildCommand(URL url) {
        String cmd = "GET " + url.getPath() + " HTTP/1.1rn";
        cmd += "Host: " + url.getHost() + "rn";
        if (this.ua != null) {
            cmd += "User-Agent: "+this.ua+"rn";
        }
        if (this.gzip == true) {
            cmd += "Accept-Encoding: gzip, deflatern";
        }
 
        //Close
        cmd+="rn";        
 
        return cmd;
    }
}

Charger une page internet avec les sockets

Au delà de l'aspect pédagogique, la class a pour but de charger rapidement des pages HTML en recueillant le maximum d'information sur la communication avec le serveur web. Pour l'exemple, nous allons nous connecter au serveur d'Ubuntu.org et charger la page HTML de téléchargement de ubuntu.
public class HttpRawSocket {
 
    public static void main(String[] args) {
        HttpRawSocket httpSocket = new HttpRawSocket();
        try {
            httpSocket.setUserAgent("Exemple java de Fobec.com");
            httpSocket.connect("http://ubuntu-fr.org/telechargement");
 
            System.out.println(httpSocket.getRequest());
            System.out.println(httpSocket.getHeader());
            System.out.println(httpSocket.getHtml());
        } catch (MalformedURLException ex) {
            Logger.getLogger(HttpRawSocket.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(HttpRawSocket.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

La requête envoyée au serveur
GET /telechargement HTTP/1.1
Host: ubuntu-fr.org
User-Agent: Exemple java de Fobec.com

La commande GET indique que l'on souhaite receptionner des données. Pour l'envoi d'un formulaire, nous aurions utiliser un POST.

L'entête de la réponse
HTTP/1.0 200 OK
Server: nginx
Content-Type: text/html; charset=utf-8
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Tue, 23 Jul 2013 15:05:15 +0000
ETag: "1374591915"
Content-Language: en
X-Generator: Drupal 7 (http://drupal.org)
Link: </telechargement>; rel="canonical",</node/14>; rel="shortlink"
Content-Length: 13978
Date: Tue, 23 Jul 2013 15:05:15 GMT
Age: 0
Cache-Control: no-cache, must-revalidate, max-age=0
Pragma: no-cache
X-Cache: MISS from ipcop.localdomain
Via: 1.0 ipcop.localdomain:800 (squid/2.6.STABLE21)
Connection: close

Le plus important est la mention 200 tout s'est bien passé !!!

Le code HTML renvoyé
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN"
"http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" version="XHTML+RDFa 1.0" dir="ltr"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/terms/"
xmlns:foaf="http://xmlns.com/foaf/0.1/"
xmlns:og="http://ogp.me/ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:sioc="http://rdfs.org/sioc/ns#"
xmlns:sioct="http://rdfs.org/sioc/types#"
xmlns:skos="http://www.w3.org/2004/02/skos/core#"
xmlns:xsd="http://www.w3.org/2001/XMLSchema#">

<head profile="http://www.w3.org/1999/xhtml/vocab">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

....

Voici le code HTML qui sera affiché dans un navigateur internet par exemple.

Optimiser et sécuriser la communication avec un socket

Le but de la class est de communiquer rapidement et facilement avec un serveur web au travers d'un socket. En production sur des taches automatiques, il faudrait en premier lieu traiter les erreurs de communication avec le serveur, à savoir les erreurs de connexion, les Time-out ou encore la reception partielle du code HTML.

Ajouter un commentaire

Les champs marqués d'un * sont obligatoires, les adresses emails se sont pas publiées.

A lire aussi

Réseaux sociaux
Présentation de l'article
Catégorie
java - class
Mise a jour
23/07/2013
Visualisation
vu 4883 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 267 articles
|BIO_PSEUDO|
Commentaires récents

Publié par max dans java

est que ce framework fonctionne pour une application web ?

Publié par Axel dans java

L'astuce de la conversion en gris se situe dans imagedst.
Le BufferedImage imagesrc contient l'image en couleur, imagedst est une image cree en nuance de gris. Lorsque l'on copie l'image colorisee...

Publié par robbie dans tuto

desole pour le message en multiple j'ai eu un ptit beug

Publié par hilflo dans tuto

Tres bon article qui montre bien les subtilites des mutualises de 1and1.
Je l'ai utilise pour un de mes sites en y ajoutant de l'url rewriting pour eviter d'avoir des parametres dans l'url avec cet...

Publié par Fobec dans java

Les images statiques sont aussi devenues payantes chez Google. Donc sans compte et une cle, l'image ne se chargera pas.
Je vous conseille de passer sur un autre fournisseur de carte, le code re...