Mini serveur HTTP en borland c++ 5

steph12358 Messages postés 149 Date d'inscription jeudi 22 avril 2004 Statut Membre Dernière intervention 10 décembre 2009 - 3 oct. 2007 à 11:21
steph12358 Messages postés 149 Date d'inscription jeudi 22 avril 2004 Statut Membre Dernière intervention 10 décembre 2009 - 4 oct. 2007 à 10:02
Bonjour

Je débute en C++ Builder 5 et dans le cadre d'un projet avec interface web je dois
développer un mini serveur HTML et multithread en plus (je dois pouvoir gérer plusieurs connexions)

J'ai fait de nombreuses recherche sur Google  mais les exemples trouvés sur le net ne sont pas portables dans cet environnement. Il en existe une pléthore sous delphi mais sous c++ builder que Pouic !

Quelqu'un a t'il des infos à ce sujet car je rame sévérement
tout ce que je sais pour l'instant c'est que je dois, à priori, utiliser un composant TServerSocket mais je doute de pouvoir faire du multithread avec ça.

PS : Je n'ai pas mis "au secours" dans le titre du sujet mais bon...

Merci d'avance

2 réponses

The_Guardian Messages postés 317 Date d'inscription vendredi 25 mai 2007 Statut Membre Dernière intervention 19 octobre 2007 1
3 oct. 2007 à 13:14
Bonjour,

Apparemment te faudra tout.

Tu devrais regarder un exemple de code fait sous delphi par exemple et ensuite essayer de traduire ça en C++
 l'autre solution c'est tout faire toi meme mais si tu débutes en C++ ça risque d'être chaud,  mais bon dans tous les cas faut que tu regardes la doc de TServerSocket et tout ce qui a trait aux sockets et dans l'API que tu utilises, le multithread après c'est pas lié aux sockets que tu utilises. fais pour le moment un truc monothread et après tu verras.

=

Une autruche ne se cuit pas aux petits lardons
0
steph12358 Messages postés 149 Date d'inscription jeudi 22 avril 2004 Statut Membre Dernière intervention 10 décembre 2009 1
4 oct. 2007 à 10:02
Bonjour the_guardian

L'aide de Borland C++ Builder c'est vraiment la misère et Google me renvoie sur des sites en japonais, allemand, roumain etc... A croire que les anglais et les français n'éprouvent pas le besoin de réinventer la poudre

Après de nouvelles recherches donc et pour prouver que je n'attends pas que les cailles tombent toutes roties J'ai commencé à écrire ça :

Mon projet ne gère que le GET et renvoie le(s) fichier(s) demandés.
Il renvoie la page "index.html" si rien n'a été précisé.
Il écoute sur le port 8080.

Marche pas trop mal si la page est "courte" et contient du texte seulement
Par contre si la page contient des liens vers des images ça fonctionne une fois sur 10

Index.html contient 2 images. Un GIF (smiley.gif) et un BMP (truc.bmp) pour voir...
Parfois les deux images arrivent, parfois 1 seule sinon aucune...
Quelquefois la même apparaît 2 fois et quelquefois elles sont inversées
(raaaahhhhh !)

En clair on est à des millions d'années lumières d'Apache et même un béotien comme moi ne saurait s'en contenter.

Voici la page index.html, ultra minimaliste

<html>
<head>
</head>

Bienvenu

vous &ecirc;tes connect&eacute; au serveur...

<hr>

</html>

voici le code Borland C++ Builder à mettre dans un form
Rem : le type du ServerSocket est "stNonBlocking". J'ai essayé l'autre valeur mais ça bloquait tout alors...
2 champs memos, une listbox pour les traces et faites rouler...

(désolé : je n'ai pas trouvé les balises utilisées sur le forum pour isoler le code du reste du message)

//---------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <vcl.h>
#include <string.h>       
#include <fcntl.h>
#include
#include <time.h>

#pragma hdrstop

#include "Unit1.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
   : TForm(Owner)
{
   MemoIn->Lines->Clear();
   ListBox1->Clear();
}

//---------------------------------------------------------------------------
__fastcall TForm1::~TForm1()
{
   //...
}

//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   //Lancement du serveur
   ServerSocket1->Active = true;
}

//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1ClientConnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
   ListBox1->Items->Add(AnsiString("ServerSocket1ClientConnect"));
   ListBox1->Items->Add( Socket->RemoteAddress );

}

//---------------------------------------------------------------------------
void __fastcall TForm1::ServerSocket1Accept(TObject *Sender,
      TCustomWinSocket *Socket)
{
   //Evénement déclenché lorsque le serveur accepte une connexion
   ListBox1->Items->Add(AnsiString("ServerSocket1Accept"));

   AnsiString req;
   char buf [1001], trav[256], textehtml [1001];
   int lu;

   //int lg = Socket->ReceiveLength();
   req = "";

   //Lecture de la requête du client
   MemoIn->Lines->Add(AnsiString("---requete du navigateur------"));

   do {
      lu = Socket->ReceiveBuf(buf, sizeof(buf));
      if (lu == -1)
         break;
      MemoIn->Lines->Add(AnsiString(buf));
      req += AnsiString(buf);
   }  while (true);
  
   MemoIn->Lines->Add(AnsiString("------------------------------"));

   //pour l'instant on ne traite que GET : extraction du fichier demandé
  
   int pos;
   pos = AnsiPos("HTTP", req);
   if (pos > 0)
      req = req.SubString(1, pos-1);
   pos = AnsiPos("GET /", req);
   if (pos > 0)
      req = req.SubString(pos+5, req.Length()-6);
   req = Trim(req);

   FichierDemande = req;

   //On aiguille sur la page par défaut
   if (FichierDemande == "")
      FichierDemande = "index.html";

   ListBox1->Items->Add(AnsiString("Fichier demandé: ")+FichierDemande);

   }
//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1GetSocket(TObject *Sender, int Socket,
      TServerClientWinSocket *&ClientSocket)
{
   //Evénement
   ListBox1->Items->Add(AnsiString("ServerSocket1GetSocket"));

}
//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1ClientDisconnect(TObject *Sender,
      TCustomWinSocket *Socket)
{
   //Evénement qui survient à la déconnexion du client.
   ListBox1->Items->Add(AnsiString("ServerSocket1ClientDisconnect"));
   ListBox1->Items->Add(AnsiString("-----------------------------"));

}
//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1ClientWrite(TObject *Sender,
      TCustomWinSocket *Socket)
{
   ListBox1->Items->Add(AnsiString("ServerSocket1ClientWrite"));

   TraiteRequete(Socket, FichierDemande);
   Sleep (50);                     //sinon plante ?!?
   Socket->Close();           //sinon ne reçoit jamais les données !?!
}

bool TForm1::TraiteRequete(TCustomWinSocket *Socket, AnsiString NomFichier)
{
AnsiString  ext;
bool result;

   //Recherche du type Mime (cf. http://hostmeister.com/mime.html)

   result = false;

   ext = UpperCase(ExtractFileExt(NomFichier));
   if ( (ext ".HTM") || (ext ".HTML") )
      result = EnvoiFichier(Socket, NomFichier, "text/html");
   if ( (ext ".JPG") || (ext ".JPEG") )
      result = EnvoiFichier(Socket, NomFichier, "image/jpeg");

   if (ext == ".GIF")
      result = EnvoiFichier(Socket, NomFichier, "image/gif");

   if (ext == ".BMP")
      result = EnvoiFichier(Socket, NomFichier, "image/bmp");
   if ( (ext ".EXE") || ( ext ".CAB") )
      result = EnvoiFichier(Socket, NomFichier, "application/octet-stream");

   return result;

}

bool TForm1::EnvoiFichier(TCustomWinSocket *Socket, AnsiString NomFichier, AnsiString TypeFichier)
{
   int id, lg;
   char  *bloc;
   AnsiString entete;
   bool resultat;

   resultat = true;

   id = open(NomFichier.c_str(), O_RDONLY|O_BINARY);
   if (id != -1)
   {
      lg = filelength (id);
      bloc = (char*)malloc (lg);
      if (bloc != NULL)
      {
         lg = read (id, bloc, lg);

         entete = "HTTP/1.0 200 OK\r\n";
         entete += "Keep-Alive: timeout=15, max=100\r\n";
         entete += "Connection: Keep-Alive\r\n";
         entete += "Content-Type: " + TypeFichier + "\r\n";
         entete += "Content-Length: " + AnsiString(lg) + "\r\n\r\n";

         //Trace des entêtes envoyés
         MemoOut->Lines->Add(entete);
         MemoOut->Lines->Add(AnsiString("----------"));

         int nbenvoi;

         nbenvoi = Socket->SendBuf( entete.c_str(), entete.Length() );
         Socket->SendBuf( bloc, lg );

         free (bloc);
      }
      close (id);
   }

   return resultat;

}

//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1Listen(TObject *Sender,
      TCustomWinSocket *Socket)
{
   //Lancement du serveur
   ListBox1->Items->Add(AnsiString("ServerSocket1Listen"));

}
//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1ThreadEnd(TObject *Sender,
      TServerClientThread *Thread)
{
   ListBox1->Items->Add(AnsiString("ServerSocket1ThreadEnd"));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1ThreadStart(TObject *Sender,
      TServerClientThread *Thread)
{
   ListBox1->Items->Add(AnsiString("ServerSocket1ThreadStart"));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1GetThread(TObject *Sender,
      TServerClientWinSocket *ClientSocket,
      TServerClientThread *&SocketThread)
{
   ListBox1->Items->Add(AnsiString("ServerSocket1GetThread"));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::ServerSocket1ClientError(TObject *Sender,
      TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
   ListBox1->Items->Add(AnsiString("ServerSocket1ClientError"));

   if (ErrorEvent==eeGeneral)
      ListBox1->Items->Add(AnsiString("'Erreur inattendue"));

   if (ErrorEvent==eeSend)
      ListBox1->Items->Add(AnsiString("Erreur écriture sur connexion socket"));

   if (ErrorEvent==eeReceive)
      ListBox1->Items->Add(AnsiString("Erreur lecture sur connexion socket"));

   if (ErrorEvent==eeConnect)
      ListBox1->Items->Add(AnsiString("'Demande connexion acceptée mais inachevée"));

   if (ErrorEvent==eeDisconnect)
      ListBox1->Items->Add(AnsiString("'Erreur fermeture connexion"));

}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button2Click(TObject *Sender)
{
   //Arrêt du serveur
   ServerSocket1->Close();
}
//---------------------------------------------------------------------------
0
Rejoignez-nous