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 3537 fois
Public
Internaute
Auteur de la publication
Fobec
Admin
Auteur de 261 articles
|BIO_PSEUDO|
Commentaires récents

Publié par space dans java

peut on avoir un meme code pour linux

Publié par Helo dans java

SVP Comment faire fonctionner le bouton pause ?

Publié par Fobec dans java

As-tu essaye sans le parametre de la cle ?
(supprimer la ligne url += "&key=" + this.ApiKey;)
A priori, cela fonctionne sans aucune authentification sur l'api ;)

Publié par Fobec dans CMS

Norton emet une alerte de type 'Suspicious.Cloud', hasard de compilation ou menace serieuse ? Faites attention en installant le logiciel.<br>Merci JM de l'avoir signaler.

Publié par olibul dans CMS

var
fn: string;

begin

Result:= False;
if strFont <> \'\' then begin

// Tester le nom: si affectation directe à TFont, modifications aléatoires