menu
  Home  ==>  articles  ==>  web  ==>  http_client   

Client HTTP - John COLIBRI.


1 - Le protocole HTTP

Nous allons présenter un projet permettant de télécharger une page Internet en utilisant le socket client, tClientSocket, fourni avec Delphi.

Depuis plus d'une décennie, de nombreuses solutions ont été proposées pour télécharger une page Internet en utilisant Delphi. Pour n'en citer que quelques unes

  • Socket Windows
  • WinInet
  • les composants NetManage (abandonnés par Delphi depuis Delphi 5)
  • les composants Indy (en vogue depuis Delphi 6
  • les composants ICS, ou les autres librairies TCP IP (Synapse etc)
Nous allons ici utiliser le composant tClientSocket fourni avec Delphi 6

Nous avons présenté plusieurs articles pour effectuer des transferts TCP-IP:

  • Programmation WinSocket : communication Client Server utilisant les API de la librairie WinSock. Le plus simple exemple de programmation socket en Delphi
  • architecture des composants Socket Delphi : l'organisation des classes de l'unité ScktComp, avec les diagrammes de classe UML et un exemple simple de transfert de fichiers utilisant tClientSocket et tServerSocket (le tClientSocket étant le composant utilisé dans cet article)
Nous organisons aussi régulièrement des formations TCP /IP:


2 - Fonctionnement HTTP

Pour télécharger une page, il faut:
  • se connecter à l'aide de notre tClientSocket au serveur distant
  • envoyer une requête ayant un format spécifique
  • lire les données envoyées par le Serveur.
Voici le détail des opérations pour charger, par exemple, la page "Formation Turbo Delphi" du site "Formation-Delphi"
  • sur le site où est hébergée la page, le Serveur HTTP attend les requêtes:

    image

  • le Client HTTP se connecte à ce serveur:

    image

  • le Serveur accepte la connection

    image

  • le Client HTTP envoie la demande de la page de formation:

    image

  • le Serveur envoie, en un ou plusieurs paquets, le contenu de la page:

    image




3 - Le Projet Delphi de téléchargement HTML

3.1 - L'utilisation directe du tClientSocket

   créez un nouveau projet Delphi
   de l'onglet "Internet", sélectionnez le tClientSocket et posez-le sur la Forme

image

   créez son événement OnConnect, qui sera appelé lorsque la connection aura été établie. C'est là que nous avons choisi d'envoyer la requête HTTP Get, après avoir préparé le tampon de réception:

var g_c_reception_bufferc_byte_bufferNil;

procedure TForm1.ClientSocket1Connect(SenderTObject;
    SocketTCustomWinSocket);
  var l_pageString;
      l_get_requestString;
  begin
    // -- send the HTTP get

    l_page:= page_edit_.Text;

    l_get_request:= 'GET 'l_page' HTTP/1.0'k_new_line
        + 'Accept: image/gif, image/x-xbitmap, image/jpeg, '
        +      ' image/pjpeg, */*'k_new_line
        + 'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; '
        +      ' Windows NT 5.1)'k_new_line
        + 'Host: 'host_edit_.Textk_new_line
        + k_new_line;

    g_c_reception_buffer.Free;
    g_c_reception_buffer:= c_byte_buffer.create_byte_buffer('reception',
        2* 1024);

    ClientSocket1.Socket.SendBuf(Pointer(l_get_request)^,
        Length(l_get_request));
  end// ClientSocket1Connect

   créez son événement OnRead. Cet événement sera appelé chaque fois que le Client reçoit un paquet du Serveur. Nous stockons ces données dans le tampon g_c_reception_buffer

procedure TForm1.ClientSocket1Read(SenderTObject;
      SocketTCustomWinSocket);
  var l_bytes_receivedInteger;
      l_remainingInteger;
      l_pt_start_receptionPointer;
  begin
    with g_c_reception_buffer do
    begin
      repeat
        // -- add the received data to the current buffer
        l_remaining:= m_buffer_sizem_write_index;

        // -- if not at least a tcp-ip chunk, increase the room
        if l_remainingk_tcp_ip_chunk
          then begin
              double_the_capacity;
              l_remaining:= m_buffer_sizem_write_index;
            end;

        l_pt_start_reception:= @ m_oa_byte_buffer[m_write_index];
        // -- get at most k_tcp_ip_chunk
        l_bytes_received:= ClientSocket1.Socket.ReceiveBuf(l_pt_start_reception^,
             k_tcp_ip_chunk);
        if l_bytes_received<= 0
          then begin
              display('  ...no_more_for_now');
              Break;
            end;

        if l_bytes_received> 0
          then Inc(m_write_indexl_bytes_received);
      until False;
    end// with g_c_reception_buffer
  end// ClientSocket1Read

   créez son événement OnDisconnect. C'est là que nous exploitons les données reçues (sauvegarde, analyse etc):

procedure TForm1.ClientSocket1Disconnect(SenderTObject;
      SocketTCustomWinSocket);
  begin
    with g_c_reception_buffer do
      save_to_file_start_end(f_exe_path'..\_data\resu.html',
          f_next_2_new_line_position(0)+ 4, m_write_index- 1);
  end// ClientSocket1Disconnect

   posez un tButton sur la Forme, créez son événement Click et tapez le code qui va lancer la requête:

procedure TForm1.connect_Click(SenderTObject);
  begin
    with ClientSocket1 do
    begin
      Close();
      Host:= host_edit_.Text;
      Port:= 80;
      Open();
    end;
  end// with ClientSocket1

   compilez, executes, cliquez "connect_"

   voici le résultat:

image



Notez que
  • comme indiqué dans l'article sur les Sockets Delphi, c'est tClientSocket.Socket qui est le véritable WinSocket, alors que tClientSocket n'est qu'une mince encapsulation objet de ce WinSocket.
  • comment avons nous déterminé les paramètres de GET HTTP ? Nous avions commencé par lire les spécifications, et comme cela ne marchait pas toujours, nous avons simplement envoyé une requête simple en utilisant Internet Explorer, mais en ayant branché auparavant le Sniffer TCP / IP qui nous a révélé le contenu exact des paquets envoyés entre Internet Explorer et le Serveur. Nous avons ensuite copié ces paramètres (Mozilla, Compatible etc) sans autre état d'âme


3.2 - La classe c_http_client

Pour pouvoir rapidement mettre en oeuvre le téléchargement depuis d'autres applications (la lecture de blogs en l'occurence), nous avons encapsulé le tClientSocket dans une CLASSe dont voici la définition:

c_http_clientclass// Forward
t_po_received_eventProcedure(p_c_http_clientc_http_clientof Object;

c_http_client=
    class(c_basic_object)
      m_c_client_sockettClientSocket;
      m_urlString;
      m_c_reception_bufferc_byte_buffer;
      m_total_received_bytesInteger;

      m_on_received_eventt_po_received_event;

      Constructor create_http_client(p_nameString);

        procedure handle_socket_error(p_c_client_sockettObject;
            p_c_winsocketTCustomWinSocket;
            p_error_eventTErrorEventvar pv_error_codeInteger);
        procedure connect;
        procedure handle_after_connection(p_c_client_sockettObject;
            p_c_winsocketTCustomWinSocket);
        procedure handle_write(p_c_client_sockettObject;
            p_c_winsocketTCustomWinSocket);
        procedure handle_read(p_c_client_sockettObject;
            p_c_winsocketTCustomWinSocket);
        procedure disconnect;
        procedure handle_after_disconnection(p_c_client_sockettObject;
            p_c_winsocketTCustomWinSocket);

      procedure download_page(p_urlString;
          p_po_received_eventt_po_received_event);

      Destructor DestroyOverride;
    end// c_http_client

Notez que:

  • l'événement m_on_received_event que nous utiliserons pour prévenir l'utilisateur de cette CLASSe que le téléchargement est terminé
  • nous avons modifié le nom des événements pour nous aligner sur la convention Alsacienne (p_c_xxx etc). Nous aurions pu utiliser Sender et Socket.


Le constructeur créé simplement le tClientSocket (la même chose qui était effectuée en posant le composant sur le Forme depuis la Palette, et initialise le tampon de réception):

Constructor c_http_client.create_http_client(p_nameString);
  begin
    Inherited create_basic_object(p_name);

    m_c_reception_buffer:= c_byte_buffer.create_byte_buffer('receive',
        2* k_tcp_ip_chunk);

    m_c_client_socket:= tClientSocket.Create(Nil);
    with m_c_client_socket do
    begin
      Port:= k_http_port;

      OnError:= handle_socket_error;
      OnConnect:= handle_after_connection;
      OnWrite:= handle_write;
      OnRead:= handle_read;
      OnDisconnect:= handle_after_disconnection;
    end// with m_c_client_socket
  end// create_http_client

Et lorsque le Serveur fermera la connection, OnDisconnect sera appelé, et cette méthode appellera la procédure de l'utilisateur de la CLASSe:

procedure c_http_client.handle_after_disconnection(
    p_c_client_sockettObjectp_c_winsocketTCustomWinSocket);
  begin
    if Assigned(m_on_received_event)
      then m_on_received_event(Self);
  end// handle_after_disconnection



Au niveau de la Forme principale, nous avons aussi ajouté (le tout figurant dans le .ZIP des sources ci-dessous):

  • une chargement dans une tListBox d'un fichier contenant plusieurs URL
  • la possibilité de visualiser le contenu du fichier .HTML téléchargé


3.3 - UML: Diagramme de Classe

Nous pouvons représenter la structure de notre mécanique par le diagramme de classe UML suivant

image



3.4 - UML: Diagramme de Séquence

Et pour visualiser "qui appelle qui", ainsi que les interactions au niveau des classes, voici le diagrame de séquence UML:

image



3.5 - Mini Manuel

Pour utiliser la version avec la CLASSe c_http_client
  • remplissez un fichier avec des URLs à télécharger
  • compilez et exécutez
  • dans l'onglet "dir_" spécifiez le fichier des URLs
  • dans l'onglet "download_"
    • cliquez "load_urls_" si la tListBox n'est pas déjà chargée
    • cliquez sur la page à télécharger
    • cliquez "save_" pour sauvegarder le fichier



4 - Améliorations

Ce programme est sans prétention. De nombreux points peuvent être mentionnés
  • les composants ICS, Indy ou autre automatisent entièrement le processus de mise en forme de la requête, et de récupération du fichier
  • à l'extrême limite du spectre, nous pouvons même utiliser le tWebBrowser, qui permet d'inclure un ActiveX Internet Explorer dans notre application. Ce qui n'est pas sans difficultés pour manipuler le contenu obtenu, et qui explique notre choix pour le tClientSocket. Mais pour le téléchargement rapide et lorsqu'il faut uniquement affichage graphiquement le contenu, le tWebBrowser reste imbattable, et nous l'utiliserons pour afficher le contenu de blogs.



5 - Télécharger le code source Delphi

Vous pouvez télécharger:

Ce .ZIP qui comprend:

  • le .DPR, la forme principale, les formes annexes eventuelles
  • les fichiers de paramètres (le schéma et le batch de création)
  • dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonaume)
Ces .ZIP, pour les projets en Delphi 6, contiennent des chemins RELATIFS. Par conséquent:
  • créez un répertoire n'importe où sur votre machine
  • placez le .ZIP dans ce répertoire
  • dézippez et les sous-répertoires nécessaires seront créés
  • compilez et exécutez
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.

La notation utilisée est la notation alsacienne qui consiste à préfixer les identificateurs par la zone de compilation: K_onstant, T_ype, G_lobal, L_ocal, P_arametre, F_unction, C_lasse. Elle est présentée plus en détail dans l'article La Notation Alsacienne



Comme d'habitude:

  • nous vous remercions de nous signaler toute erreur, inexactitude ou problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
  • tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
  • plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :
    Nom :
    E-mail :
    Commentaires * :
     

  • et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.



6 - L'auteur

John COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le conseil (composants, architecture, test) et la formation. Son site contient des articles avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client.
Créé: mar-06. Maj: aou-15  148 articles, 471 sources .ZIP, 2.021 figures
Contact : John COLIBRI - Tel: 01.42.83.69.36 / 06.87.88.23.91 - email:jcolibri@jcolibri.com
Copyright © J.Colibri   http://www.jcolibri.com - 2001 - 2015
Retour:  Home  Articles  Formations  Développement Delphi  Livres  Pascalissime  Liens  Download
l'Institut Pascal

John COLIBRI

+ Home
  + articles_avec_sources
    + bases_de_donnees
    + web_internet_sockets
      – http_client
      – moteur_de_recherche
      – javascript_debugger
      + asp_net
      – client_serveur_tcp
      – site_editor
      – pascal_to_html
      – cgi_form
      + les_logs_http_bruts
      + les_blogs
      – intraweb_tutorial
      + services_web
      – serveur_web_iis
      – client_serveur_pop3
    + prog_objet_composants
    + office_com_automation
    + colibri_utilities
    + uml_design_patterns
    + graphique
    + delphi
    + outils
    + firemonkey
    + vcl_rtl
    + colibri_helpers
    + colibri_skelettons
  + formations
  + developpement_delphi
  + présentations
  + pascalissime
  + livres
  + entre_nous
  – télécharger

contacts
plan_du_site
– chercher :

RSS feed  
Blog

Formation Delphi xe3 complete L'outil de développpement, le langage de programmation, les composants, les bases de données et la programmation Internet - 5 jours