Publié le 23/07/2013
Auteur Fobec
Réseaux sociaux
0 partages
0 tweets
2 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 3422 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 261 articles
|BIO_PSEUDO|
Commentaires récents

Publié par Yannick dans tuto

Sur un de mes sites j'ai vraiment du mal a gerer le gzip sur 1and1, Je vais tout de suite tester tout ca et je vous tiens informe :)

Publié par jyfv dans CMS

hgfdhgfdhgf

Publié par Tchat dans news

Analyses interessantes.
J'ai constate aussi des comportements etranges de Google concernant les placements des sites sur leurs requetes.
Par contre j'ai remarque que Google ne tient pl...

Publié par samir dans CMS

merci

Publié par ric dans CMS

c\'est la première fois que j\'utilise ce logiciel