[Résolu] Serveur html en soket TCP

Serveur html en soket TCP [Résolu] - C - Programmation

Marsh Posté le 04-02-2008 à 20:57:07    

Voila mon problème : je dois générer un affichage html pour un client web (firefox/ie) à partir d'un programme en C qui utilise du socket TCP, de plus cela doit être threadé.
Voici où j'en suis :
 

Code :
  1. /* #################################
  2.         Serveur thread http
  3.                 affichage adresse IP
  4.    ################################# */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <netinet/in.h>
  8. #include <string.h>
  9. #include <pthread.h>
  10.        
  11.         struct sockaddr_in adresse;
  12.         int longueur=sizeof(struct sockaddr_in);
  13.         char connexion[512]="GET / HTTP/1.1\nHost: localhost:2083\nUser-Agent:
  14. Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111
  15. Firefox/1.0\nAccept:
  16. text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\nAccept-Language:
  17. en-us,en;q=0.5\nAccept-Encoding: gzip,deflate\nAccept-Charset:
  18. ISO-8859-1,utf-8;q=0.7,*;q=0.7\nKeep-Alive: 300\nConnection:
  19. keep-alive\nCache-Control: max-age=0\n"; // message d'envoi
  20.         char html[256]="<HTML>\n\t<HEAD></HEAD>\n\t<TITLE>Ma page</TITLE>\n\t<BODY>Mon
  21. contenu</BODY>\n</HTML>\n";
  22.         char message2[128]=""; // pour r??cup??rer la r??ponse
  23.         pthread_t tid;
  24. void *serverthread(void *desc2)
  25. {
  26.         int a=48;
  27.         // reception
  28.         if(read(desc2,(void *)message2,128,0,(struct sockaddr *)&adresse,&longueur)==0)
  29.         {
  30.                 perror("Erreur recvfrom\n" );
  31.                 exit(3);
  32.         }
  33.         else
  34.         {
  35.                 printf("%s\n", message2);
  36.                 if(a=(strcmp(message2, "GET" ))==0)
  37.                 {
  38.                         printf("salut bibi %d\n",a);
  39.                 }
  40.                 else
  41.                 {
  42.                         printf("salut bobo %d\n",a);
  43.                 }
  44.         }
  45.         sleep(3);
  46. //      printf("Message recu de %s : %s\n", inet_ntoa(adresse.sin_addr.s_addr),
  47. message2);
  48.         // emission
  49.         if(write(desc2,(void *)connexion,strlen(connexion),0,(struct sockaddr
  50. *)&adresse,sizeof(adresse))==0)
  51.         {
  52.                  perror("Erreur sendto\n" );
  53.                  exit(2);
  54.         }
  55.         else
  56.         {
  57.                 printf("sendto ok\n" );
  58. //                printf("%s\n", connexion);
  59.         }
  60.         if(write(desc2,(void *)html,strlen(html),0,(struct sockaddr
  61. *)&adresse,sizeof(adresse))==0)
  62.         {
  63.                  perror("Erreur sendto\n" );
  64.                  exit(2);
  65.         }
  66.         else
  67.         {
  68.                 printf("sendto ok\n" );
  69.                 printf("%s\n", html);
  70.         }
  71.         sleep(60);
  72.         close(desc2);
  73.         printf("Fin du thread\n" );
  74.        
  75. }
  76. int main()
  77. {
  78.             int desc, desc2 ;
  79.         desc=socket(AF_INET,SOCK_STREAM,0);
  80.         // Structure Serveur
  81.         adresse.sin_family=AF_INET;
  82.         adresse.sin_addr.s_addr=INADDR_ANY;
  83.         adresse.sin_port=htons(2083);
  84.         // Attachement en local (bind)
  85.         if(bind(desc,(struct sockaddr *)&adresse,longueur)==-1)
  86.         {
  87.                 perror("Erreur bind()\n" );
  88.                 exit(1);
  89.         }
  90.         // Ecoute
  91.         if(listen(desc,5)==-1)
  92.         {
  93.                 perror("Erreur a l'ecoute\n" );
  94.                 exit(1);
  95.         }
  96.         while(1)
  97.         {
  98.                 if ((desc2=accept(desc, (struct sockaddr *)&adresse, &longueur)) < 0)
  99.                 {
  100.                         perror("Erreur sur accept()\n" );
  101.                         exit (1);
  102.                 }
  103.                 if(pthread_create(&tid, NULL, serverthread, (void *)desc2)!=0)
  104.                 {
  105.                         perror("Erreur durant la cr??ation du thread\n" );
  106.                         exit(1);
  107.                 }
  108.                 close(desc2);
  109.         }
  110.         close(desc2);
  111.         pause();
  112.         return(0);
  113. }


 
En plus si je fais un get en telnet je dois voir l'entete http suivante : "GET / HTTP/1.1\nHost: localhost:2083\nUser-Agent:
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111
Firefox/1.0\nAccept:
text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\nAccept-Language:
en-us,en;q=0.5\nAccept-Encoding: gzip,deflate\nAccept-Charset:
ISO-8859-1,utf-8;q=0.7,*;q=0.7\nKeep-Alive: 300\nConnection:
keep-alive\nCache-Control: max-age=0\n"
 
le port utilisé doit etre 12345 de façon à avoir l'affichage suivant qui est généré : "<HTML>\n\t<HEAD></HEAD>\n\t<TITLE>Ma page</TITLE>\n\t<BODY>Mon
contenu</BODY>\n</HTML>\n"
 
Voila j'espere que vous pourrez me donner un coup de main !
 
PS : de plus il y a un problème de cache, au bout d'un moment les threadent posent problèmes... ceci est un exo noté donc toute aide est la bienvenue !

Message cité 1 fois
Message édité par yad40 le 25-02-2008 à 21:21:19
Reply

Marsh Posté le 04-02-2008 à 20:57:07   

Reply

Marsh Posté le 04-02-2008 à 21:07:35    

En gros tu dois faire un mini-server web multi-threadé ? Si le C t'es imposé, regarde du coté de FastCGI + lighttpd ou Apache.

Reply

Marsh Posté le 04-02-2008 à 21:09:47    

Oui en gros c'est ça un mini serveur multi - threadé qui envoie du code sur un client web. Et le C est imposé ainsi que cette structure même si elle n'est pas très claire...
 
Merci de la réponse rapide
 
EDIT
 
Après avoir cherché je ne trouve pas de code sur lequel m'inspirer...


Message édité par yad40 le 04-02-2008 à 21:20:40
Reply

Marsh Posté le 04-02-2008 à 21:23:20    

Ce n'est pas vraiment de l'inspiration qu'il faut chercher, mais plutôt de la réutilisation. Recoder ces technos, tu en as pour 2 ans avant d'avoir un truc stable.

Reply

Marsh Posté le 04-02-2008 à 21:26:55    

Ce n'est pas à moi qu'il faut le dire mais à ces gens dans les bureaux qui font les programmes scolaires...
 
Si ça ne tenait qu'a moi je leur enverrais un apache déja compilé !
 
Mais là il faut que je code ce générateur c'est bien pour ça que je fais appel aux compétences de ce forum... c'est assez habérant de recoder la roue mais c'est comme ça si je ne le fait pas je peux dire adieu a mes études ^^
 
Toute aide est la bienvenue lorsqu'on est dans cette situation !

Reply

Marsh Posté le 05-02-2008 à 15:43:04    

yad40 a écrit :

Voila mon problème : je dois générer un affichage html pour un client web (firefox/ie) à partir d'un programme en C qui utilise du socket TCP, de plus cela doit être threadé.
Voici où j'en suis :


Ce code ne compile absolument pas.  (read() et write() ne s'utilisent pas du tout comme ça...)

 

Voici une version compilable sous Windows et Linux :

Code :
  1. /* #################################
  2.         Serveur thread http
  3.                 affichage adresse IP
  4.    ################################# */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #ifdef __cplusplus
  9. #error Be sure you are using a C compiler...
  10. #endif
  11. #if defined (WIN32)
  12. #include <winsock2.h>
  13. #elif defined (linux) || defined (_POSIX_VERSION) || defined (_POSIX2_C_VERSION)\
  14. || defined (_XOPEN_VERSION)
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #include <arpa/inet.h>
  19. #include <unistd.h>             /* close */
  20. #define INVALID_SOCKET -1
  21. #define SOCKET_ERROR -1
  22. #define closesocket(s) close (s)
  23. typedef int SOCKET;
  24. typedef struct sockaddr_in SOCKADDR_IN;
  25. typedef struct sockaddr SOCKADDR;
  26. #else
  27. #error not defined for this platform
  28. #endif
  29. #include <pthread.h>
  30. /* http://delahaye.emmanuel.free.fr/clib/ */
  31. #include "psleep/inc/psleep.h"
  32. /* message d'envoi */
  33. char connexion[] =
  34.    "GET / HTTP/1.1\n"
  35.    "Host: localhost:2083\nUser-Agent:Mozilla/5.0 "
  36.    "(X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111Firefox/1.0\n"
  37.    "Accept:text/xml,application/xml,application/xhtml+xml,text/html;"
  38.    "q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\n"
  39.    "Accept-Language:en-us,en;q=0.5\n"
  40.    "Accept-Encoding: gzip,deflate\n"
  41.    "Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.7\n"
  42.    "Keep-Alive: 300\n" "Connection:keep-alive\n" "Cache-Control: max-age=0\n";
  43. char html[] = "<HTML>\n"
  44.    "\t<HEAD></HEAD>\n"
  45.    "\t<TITLE>Ma page</TITLE>\n" "\t<BODY>Moncontenu</BODY>\n" "</HTML>\n";
  46. struct cli
  47. {
  48.    struct sockaddr_in adresse;
  49.    size_t longueur;
  50.    SOCKET desc;
  51.    pthread_t tid;
  52. };
  53. void *serverthread (void *data)
  54. {
  55.    struct cli *p_cli = data;
  56.    /* reception */
  57.    char message2[128] = "";     /* pour recuperer la reponse */
  58.    int n = recv (p_cli->desc, message2, sizeof message2 - 1, 0);
  59.    if (n == 0)
  60.    {
  61.       perror ("Erreur recv\n" );
  62.       exit (EXIT_FAILURE);
  63.    }
  64.    else
  65.    {
  66.       int a = 48;
  67.       message2[n] = 0;
  68.       printf ("%s\n", message2);
  69.       if (strcmp (message2, "GET" ) == 0)
  70.       {
  71.          printf ("salut bibi %d\n", a);
  72.       }
  73.       else
  74.       {
  75.          printf ("salut bobo %d\n", a);
  76.       }
  77.    }
  78.    msleep (3000);
  79. #if DBG
  80.    printf ("Message recu de %s : %s\n", inet_ntoa (adresse.sin_addr.s_addr),
  81.            message2);
  82. #endif
  83.    /* emission */
  84.    if (send (p_cli->desc, connexion, strlen (connexion), 0) == 0)
  85.    {
  86.       perror ("Erreur send\n" );
  87.       exit (EXIT_FAILURE);
  88.    }
  89.    else
  90.    {
  91.       printf ("send ok\n" );
  92. /* printf("%s\n", connexion); */
  93.    }
  94.    if (send (p_cli->desc, html, strlen (html), 0) == 0)
  95.    {
  96.       perror ("Erreur send\n" );
  97.       exit (EXIT_FAILURE);
  98.    }
  99.    else
  100.    {
  101.       printf ("send ok\n" );
  102.       printf ("%s\n", html);
  103.    }
  104.    msleep (60000);
  105.    closesocket (p_cli->desc);
  106.    printf ("Fin du thread\n" );
  107.    free (p_cli);
  108.    return NULL;
  109. }
  110. int serveur (void)
  111. {
  112.    SOCKET desc = socket (AF_INET, SOCK_STREAM, 0);
  113.    struct sockaddr_in adresse;
  114.    if (desc == INVALID_SOCKET)
  115.    {
  116.       perror ("SRV: Erreur sur socket()\n" );
  117.       exit (EXIT_FAILURE);
  118.    }
  119.    /* Structure Serveur */
  120.    adresse.sin_family = AF_INET;
  121.    adresse.sin_addr.s_addr = INADDR_ANY;
  122.    adresse.sin_port = htons (2083);
  123.    /* Attachement en local (bind) */
  124.    if (bind (desc, (struct sockaddr *) &adresse, sizeof (struct sockaddr_in))
  125.        == SOCKET_ERROR)
  126.    {
  127.       perror ("Erreur bind()\n" );
  128.       exit (1);
  129.    }
  130.    /* Ecoute */
  131.    if (listen (desc, 5) == SOCKET_ERROR)
  132.    {
  133.       perror ("SRV : Erreur a l'ecoute\n" );
  134.       exit (EXIT_FAILURE);
  135.    }
  136.    while (1)
  137.    {
  138.       struct cli *p_cli = malloc (sizeof *p_cli);
  139.       if (p_cli != NULL)
  140.       {
  141.          p_cli->longueur = sizeof p_cli->adresse;
  142.          p_cli->desc =
  143.             accept (desc, (struct sockaddr *) &p_cli->adresse,
  144.                     &p_cli->longueur);
  145.          if (p_cli->desc == INVALID_SOCKET)
  146.          {
  147.             perror ("SRV : Erreur sur accept()\n" );
  148.             exit (EXIT_FAILURE);
  149.          }
  150.          {
  151.             if (pthread_create (&p_cli->tid, NULL, serverthread, p_cli) != 0)
  152.             {
  153.                perror ("SRV : Erreur durant la creation du thread\n" );
  154.                exit (EXIT_FAILURE);
  155.             }
  156.          }
  157.       }
  158.    }
  159.    closesocket (desc);
  160.    return 0;
  161. }
  162. int main (void)
  163. {
  164.    int ret;
  165. #if defined (WIN32)
  166.    WSADATA wsa_data;
  167.    int err = WSAStartup (MAKEWORD (2, 2), &wsa_data);
  168.    if (!err)
  169.    {
  170.       puts ("WIN: winsock2: OK" );
  171. #else
  172.    int err;
  173. #endif
  174.    serveur ();
  175. #if defined (WIN32)
  176.    WSACleanup ();
  177. }
  178. #endif
  179. if (err)
  180. {
  181.    ret = EXIT_FAILURE;
  182. }
  183. else
  184. {
  185.    ret = EXIT_SUCCESS;
  186. }
  187. return ret;
  188. }


Il faut fournir un contexte individuel à chaque thread.

 

Il ne faut pas fermer le socket client tout de suite après avoir lancé le thread... En fait, tu as prévu une fermeture dans le thread après 60s. C'est un peu gore comme méthode, mais ça permet de démarrer. J'en profite pour libérer le contexte.

 

Voici ce que je reçois sur le telnet :


   GET / HTTP/1.1
                 Host: localhost:2083
                                     User-Agent:Mozilla/5.0 (X11; U; Linux i686;
 en-US; rv:1.7.5) Gecko/20041111Firefox/1.0
                                           Accept:text/xml,application/xml,appli
cation/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
                                                                     Accept-Lang
uage:en-us,en;q=0.5
                   Accept-Encoding: gzip,deflate
                                                Accept-Charset:ISO-8859-1,utf-8;
q=0.7,*;q=0.7
             Keep-Alive: 300
                            Connection:keep-alive
                                                 Cache-Control: max-age=0
                                                                         <HTML>

 

<HEAD></HEAD>
                <TITLE>Ma page</TITLE>
                                        <BODY>Moncontenu</BODY>
                                                               </HTML>

 


et voici ce qu'affiche le serveur au bout d'une minute :


WIN: winsock2: OK
G
salut bobo 48
send ok
send ok
<HTML>
        <HEAD></HEAD>
        <TITLE>Ma page</TITLE>
        <BODY>Moncontenu</BODY>
</HTML>

 

Fin du thread


Attention, je ne connais pas bien le protocole HTTP, mais il semble qu'il ne soit pas respecté, notamment les fins de lignes etc.


Message édité par Emmanuel Delahaye le 05-02-2008 à 16:42:31

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 05-02-2008 à 19:28:05    

Merci cela me sera bcp utile !
 
J'ai fait ça durant la journée ça :

Code :
  1. /* ----------------------------------------
  2.       Serveur socket  
  3.  thread http html  
  4. ------------------------------------------- */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <netinet/in.h>
  8. #include <string.h>
  9. #include <pthread.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. char html[65000];
  14. char *msgerror;
  15. struct sockaddr_in adresse;
  16. int longueur=sizeof(struct sockaddr_in);
  17. pthread_t tid;
  18. char message2[512]="\0";
  19. int ouvrir(char* url, int desc2)
  20. {
  21. int i=0;
  22. do
  23. {
  24.  i++;
  25. }
  26. while(url[i]!='\0');
  27. printf("%s\n", url);
  28. i--;
  29. if(url[i]!='l' && url[i-1]!='m' && url[i-2]!='t' && url[i-3]!='h' && url[i-4]!='.')
  30. {
  31.  url[i+1]='/';
  32.  url[i+2]='i';
  33.  url[i+3]='n';
  34.  url[i+4]='d';
  35.  url[i+5]='e';
  36.  url[i+6]='x';
  37.  url[i+7]='.';
  38.  url[i+8]='h';
  39.  url[i+9]='t';
  40.  url[i+10]='m';
  41.  url[i+11]='l';
  42.  url[i+12]='\0';
  43. }
  44. if(url[i]=='/')
  45. {
  46.  url[i+1]='i';
  47.  url[i+2]='n';
  48.  url[i+3]='d';
  49.  url[i+4]='e';
  50.  url[i+5]='x';
  51.  url[i+6]='.';
  52.  url[i+7]='h';
  53.  url[i+8]='t';
  54.  url[i+9]='m';
  55.  url[i+10]='l';
  56.  url[i+11]='\0';
  57. }
  58. int d,plop=0;
  59. char c;
  60. if((d=open(url, O_RDONLY))==-1)
  61. {
  62.  perror("Erreur open()" );
  63.  msgerror="<h3>Erreur 404, Fichier ou Dossier non trouv&eacute;</h3>\n";
  64.  if(write(desc2,(void *)msgerror,strlen(msgerror),0,(struct sockaddr *)&adresse,sizeof(adresse))==0)
  65.         {
  66.                  perror("Erreur write()" );
  67.                  exit(2);
  68.         }
  69.  memset(msgerror, 0, sizeof(msgerror));
  70.  return(5);
  71. }
  72. else
  73. {
  74.  while(read(d, &c, sizeof(char))!=0)
  75.  {
  76.   if (c!='\n')
  77.   {
  78.    html[plop]=c;
  79.    plop++;
  80.   }
  81.  }
  82. }
  83. close(d);
  84. return(0);
  85. }
  86. void *serverthread(desc2)
  87. {
  88. printf("thread lancé\n" );
  89. printf("Lecture des informations emises par le client\n" );
  90.         if(read(desc2,(void *)message2,512,0,(struct sockaddr *)&adresse,&longueur)==0)
  91.         {
  92.                 perror("Erreur read()" );
  93.                 exit(3);
  94.         }
  95. // printf("%s\n",message2);
  96. char *result = NULL;
  97. char *url=NULL;
  98. char chemin[256] = "\0";
  99. char root[31]="/home/francois/Bureau/C/C/TCP\0";
  100. result = strtok(message2, "GET " );
  101. strcpy(chemin, result);
  102. result = strtok(result, " HTTP" );
  103. url = strcat(root , result);
  104. int opn=5;
  105. opn = ouvrir(url, desc2);
  106. if(opn==0)
  107.         if(write(desc2,(void *)html,strlen(html),0,(struct sockaddr *)&adresse,sizeof(adresse))==0)
  108.         {
  109.                  perror("Erreur write()" );
  110.                  exit(2);
  111.         }
  112.  memset(html, 0, sizeof(html));
  113.         // emission
  114.         close(desc2);
  115. printf("connexion fermée\n" );
  116. printf("thread terminé\n" );
  117. pthread_exit((int *)tid);
  118. }
  119. int main()
  120. {
  121.      int desc, desc2;
  122.         desc=socket(AF_INET,SOCK_STREAM,0);
  123.         // Structure Serveur
  124.         adresse.sin_family=AF_INET;
  125.         adresse.sin_addr.s_addr=INADDR_ANY;
  126.         adresse.sin_port=htons(4195);
  127. // Attachement en local (bind)
  128.         if(bind(desc,(struct sockaddr *)&adresse,longueur)==-1)
  129.         {
  130.  perror("Erreur bind()" );
  131.  exit(1);
  132. }
  133. printf("serveur attaché en local\n" );
  134.         // Ecoute
  135.         if(listen(desc,5)==-1)
  136.         {
  137.  perror("Erreur listen()" );
  138.  exit(1);
  139. }
  140. printf("Serveur en écoute\n" );
  141.         while(1)
  142.         {
  143.                 if((desc2=accept(desc, (struct sockaddr *)&adresse, &longueur)) < 0)
  144.                 {
  145.                         perror("Erreur sur accept()" );
  146.                         exit(1);
  147.                 }
  148.  printf("connexion acceptée\n" );
  149.                 if(pthread_create(&tid, NULL, serverthread, (void *)desc2)!=0)
  150.                 {
  151.                         perror("Erreur sur pthread_create()" );
  152.                         exit(1);
  153.                 }
  154.  printf("connexion fermée\n" );
  155.         }
  156.         close(desc2);
  157.         pause();
  158.         return(0);
  159. }


 
Le professeur veut qu'en plus le chemin absolu de l'endroit où sont les fichiers .html et le numéro de port soient dans un fichier.conf.
Que les logs de ce qui se passe soient répertoiré dans un fichier dont le nom est paramétrable dans le .conf.
Que les variables globales soient protégées.
 
Actuellement la partie affichage marche sans problèmes par contre si je tape http://localhost:port/un-dossier-o [...] existe-pas j'ai une erreur de segmentation et pas moyen de trouver une fonction si fichier/dossier existe !
 
A l'heure où j'écris ce post, je n'ai pas encore regardé le code de Emmanuel Delahaye de près je le fait sur l'heure !

Reply

Marsh Posté le 06-02-2008 à 13:20:28    

Si le fichier n'existe pas, open va renvoyer -1 et positionner errno à ENOENT. Attention car tu as aussi des cas similaires qui renverront d'autres errno, par exemple ENTDIR si le un des éléments du path du fichier n'est pas un répertoire (c'est par exemple un fichier normal).
 
Tu peux aussi faire un stat() pour tester l'existence du fichier sans l'ouvrir.

Reply

Marsh Posté le 07-02-2008 à 09:20:01    

Merci je vois ça ce WE et je vous tient au courant !

Reply

Marsh Posté le 13-02-2008 à 21:20:07    

Bonsoir, après avoir passé pas mal de temps sur mon bout de code j'en suis là :

Code :
  1. /* ----------------------------------------
  2.       Serveur socket  
  3.  thread http html  
  4. ------------------------------------------- */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <netinet/in.h>
  8. #include <string.h>
  9. #include <pthread.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. char html[65000];
  14. struct sockaddr_in adresse;
  15. int longueur=sizeof(struct sockaddr_in);
  16. pthread_t tid;
  17. char root[128];
  18. char logg[32];
  19. char port[5];
  20. int ouvrir_conf()
  21. {
  22. int d,j=0,i=0;
  23. char c;
  24. char conf[1024];
  25. if((d=open("http.conf", O_RDONLY))==-1)
  26. {
  27.  perror("Erreur open() fichier de configuration" );
  28.  exit(3);
  29. }
  30. else
  31. {
  32.  while(read(d, &c, sizeof(char))!=0)
  33.  {
  34.   conf[j]=c;
  35.   j++;
  36.  }
  37.  conf[j]='\0';
  38.  close(d);
  39.  j=0;
  40.  do
  41.  {
  42.   if((conf[j]=='=') && (conf[j-1]=='t') && (conf[j-2]=='r') && (conf[j-3]=='o') && (conf[j-4]=='p'))
  43.   {
  44.    do
  45.    {
  46.     port[i]=conf[j+1+i];
  47.     i++;
  48.    }
  49.    while(conf[j+1+i]!='\n');
  50.    port[i]='\0';
  51.    i=0;
  52.   }
  53.   if((conf[j]=='=') && (conf[j-1]=='g') && (conf[j-2]=='o') && (conf[j-3]=='l'))
  54.   {
  55.    do
  56.    {
  57.     logg[i]=conf[j+1+i];
  58.     i++;
  59.    }
  60.    while(conf[j+1+i]!='\n');
  61.    logg[i]='\0';
  62.    i=0;
  63.   }
  64.   if((conf[j]=='=') && (conf[j-1]=='t') && (conf[j-2]=='o') && (conf[j-3]=='o') && (conf[j-4]=='r'))
  65.   {
  66.    do
  67.    {
  68.     root[i]=conf[j+1+i];
  69.     i++;
  70.    }
  71.    while(conf[j+1+i]!='\n');
  72.    root[i]='\0';
  73.    i=0;
  74.   }
  75.   j++;
  76.  }
  77.  while(conf[j]!='\0');
  78. }
  79. return(0);
  80. }
  81. int ouvrir(char* url, int desc2)
  82. {
  83. int i=0;
  84. do
  85. {
  86.  i++;
  87. }
  88. while(url[i]!='\0');
  89. printf("%s\n", url);
  90. i--;
  91. if(url[i]!='l' && url[i-1]!='m' && url[i-2]!='t' && url[i-3]!='h' && url[i-4]!='.')
  92. {
  93.  url[i+1]='/';
  94.  url[i+2]='i';
  95.  url[i+3]='n';
  96.  url[i+4]='d';
  97.  url[i+5]='e';
  98.  url[i+6]='x';
  99.  url[i+7]='.';
  100.  url[i+8]='h';
  101.  url[i+9]='t';
  102.  url[i+10]='m';
  103.  url[i+11]='l';
  104.  url[i+12]='\0';
  105. }
  106. if(url[i]=='/')
  107. {
  108.  url[i+1]='i';
  109.  url[i+2]='n';
  110.  url[i+3]='d';
  111.  url[i+4]='e';
  112.  url[i+5]='x';
  113.  url[i+6]='.';
  114.  url[i+7]='h';
  115.  url[i+8]='t';
  116.  url[i+9]='m';
  117.  url[i+10]='l';
  118.  url[i+11]='\0';
  119. }
  120. printf("Page a affichée : %s\n", url);
  121. int d,j=0;
  122. char c;
  123. int fp=0;
  124. char msgerror[1024] = "<h3>Erreur 404, Fichier ou Dossier non trouv&eacute;</h3>\0";;
  125. if ((d=open(url, O_RDONLY))==-1)
  126. {
  127.  perror("Erreur open() fichier html introuvable" );
  128.  if(write(desc2,(void *)msgerror,strlen(msgerror),0,(struct sockaddr *)&adresse,sizeof(adresse))==0)
  129.  {
  130.          perror("Erreur write() message d'erreur" );
  131.   memset(url, 0, sizeof(url));
  132.          exit(2);
  133.  }
  134. }
  135. else
  136. {
  137.  if((d=open(url, O_RDONLY))!=-1)
  138.  {
  139.   while(read(d, &c, sizeof(char))!=0)
  140.   {
  141.    if (c!='\n')
  142.    {
  143.     html[j]=c;
  144.     j++;
  145.    }
  146.   }
  147.  }
  148.  close(d);
  149. }
  150. memset(url, 0, sizeof(url));
  151. return(0);
  152. }
  153. void *serverthread(desc2)
  154. {
  155. printf("thread lancé\n" );
  156. printf("Lecture des informations emises par le client\n" );
  157. char msgrc[512];
  158.         if(read(desc2,(void *)msgrc,512,0,(struct sockaddr *)&adresse,&longueur)==0)
  159.         {
  160.                 perror("Erreur read()" );
  161.                 exit(3);
  162.         }
  163. char *result = NULL;
  164. char *url=NULL;
  165. char chemin[256] = "\0";
  166. int opn;
  167. result = strtok(msgrc, "GET " );
  168. strcpy(chemin, result);
  169. result = strtok(result, " HTTP" );
  170. url = strcat(root , result);
  171. if((opn=ouvrir(url, desc2))==0)
  172.         if(write(desc2,(void *)html,strlen(html),0,(struct sockaddr *)&adresse,sizeof(adresse))==0)
  173.         {
  174.                  perror("Erreur write()" );
  175.                  exit(2);
  176.         }
  177.  memset(html, 0, sizeof(html));
  178.         // emission
  179. printf("thread terminé\n" );
  180.         close(desc2);
  181. printf("Connexion fermée\n" );
  182. pthread_exit((int *)tid);
  183. }
  184. int main()
  185. {
  186. int opn=5;
  187. opn=ouvrir_conf();
  188. printf("Chemin des Sites web : %s\n", root);
  189. printf("Chemin du fichier de log : %s\n", logg);
  190. printf("Numéro du port : %s\n", port);
  191.      int desc, desc2;
  192.         desc=socket(AF_INET,SOCK_STREAM,0);
  193.         // Structure Serveur
  194.         adresse.sin_family=AF_INET;
  195.         adresse.sin_addr.s_addr=INADDR_ANY;
  196.         adresse.sin_port=htons(atoi(port));
  197. // Attachement en local (bind)
  198.         if(bind(desc,(struct sockaddr *)&adresse,longueur)==-1)
  199.         {
  200.  perror("Erreur bind()" );
  201.  exit(1);
  202. }
  203. printf("serveur attaché en local\n" );
  204.         // Ecoute
  205.         if(listen(desc,5)==-1)
  206.         {
  207.  perror("Erreur listen()" );
  208.  exit(1);
  209. }
  210. printf("Serveur en écoute\n" );
  211.         while(1)
  212.         {
  213.                 if((desc2=accept(desc, (struct sockaddr *)&adresse, &longueur)) < 0)
  214.                 {
  215.                         perror("Erreur sur accept()" );
  216.                         exit(1);
  217.                 }
  218.  printf("Connexion acceptée\n" );
  219.                 if(pthread_create(&tid, NULL, serverthread, (void *)desc2)!=0)
  220.                 {
  221.                         perror("Erreur sur pthread_create()" );
  222.                         exit(1);
  223.                 }
  224.         }
  225.         pause();
  226.         return(0);
  227. }


 
J'ai encore quelques petites choses a gérer :
1) Une erreur quand on tape une url non valide (un fichier qui n'existe pas) : erreur dans le write() de :

Code :
  1. char msgerror[1024] = "<h3>Erreur 404, Fichier ou Dossier non trouv&eacute;</h3>\0";;
  2. if ((d=open(url, O_RDONLY))==-1)
  3. {
  4.  perror("Erreur open() fichier html introuvable" );
  5.  if(write(desc2,(void *)msgerror,strlen(msgerror),0,(struct sockaddr *)&adresse,sizeof(adresse))==0)
  6.  {
  7.          perror("Erreur write() message d'erreur" );
  8.   memset(url, 0, sizeof(url));
  9.          exit(2);
  10.  }
  11. }


et je ne vois pas où elle est...
2) Tuer proprement le/les processus avec ctrl+c
3) Gérer la libération du port lorsque le serveur est en erreur et arrive sur un exit();
4) Recharger le fichier de configuration à la reception du signal SIGUP (ceci est uine énigme pour moi...)
5) Rajouter pour chaque perror et printf de "ce que fait le serveur", l'ip de l'utilisateur et l'heure
6) Rediriger les perror et printf de "ce que fait le serveur" dans le fichier de log
 
Voila je merci d'avance pour toute aide !

Reply

Marsh Posté le 13-02-2008 à 21:20:07   

Reply

Marsh Posté le 14-02-2008 à 09:28:29    

1) C'est quoi ce write à 6 arguments ?
2) man sigaction
4) C'est SIGHUP avec un H
6) Tu peux regarder du côté de dup2 pour rediriger STDERR vers le fichier

Reply

Marsh Posté le 14-02-2008 à 11:10:23    

merci je vais voir ça !
 
EDIT : En effet le write() était bien le problème
Je vois le reste demain dans le journée


Message édité par yad40 le 14-02-2008 à 18:34:29
Reply

Marsh Posté le 19-02-2008 à 09:39:44    

Bon merci à tous pour votre aide, j'arrive à la fin de mon programme !
 
Je voudrais savoir ce que vous en pensez, ce que vous rajouteriez, si il y a des choses qui vous paraissent incorrectes etc...
 

Code :
  1. /* ----------------------------------------
  2.       Serveur socket  
  3.  thread http html  
  4. gcc http.c -D_REENTRANT -lpthread -o http
  5. ------------------------------------------- */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <netinet/in.h>
  9. #include <string.h>
  10. #include <pthread.h>
  11. #include <sys/types.h>
  12. #include <sys/stat.h>
  13. #include <fcntl.h>
  14. #include <signal.h>
  15. #include <unistd.h>
  16. #include <time.h>
  17. char html[65000];
  18. int desc;
  19. struct sockaddr_in adresse;
  20. int longueur=sizeof(struct sockaddr_in);
  21. pthread_t tid;
  22. char root[128];
  23. char logg[32];
  24. char port[5];
  25. void heure()
  26. {
  27. time_t t;
  28. struct tm *tm;
  29. time(&t);
  30. printf("%s\t",ctime(&t));
  31. }
  32. void ouvrir_conf()
  33. {
  34. int d,j=0,i=0;
  35. char c;
  36. char conf[1024];
  37. if((d=open("http.conf", O_RDONLY))==-1)
  38. {
  39.  heure();
  40.  perror("Erreur open() fichier de configuration" );
  41.  exit(3);
  42. }
  43. else
  44. {
  45.  while(read(d, &c, sizeof(char))!=0)
  46.  {
  47.   conf[j]=c;
  48.   j++;
  49.  }
  50.  conf[j]='\0';
  51.  close(d);
  52.  j=0;
  53.  do
  54.  {
  55.   if((conf[j]=='=') && (conf[j-1]=='t') && (conf[j-2]=='r') && (conf[j-3]=='o') && (conf[j-4]=='p'))
  56.   {
  57.    do
  58.    {
  59.     port[i]=conf[j+1+i];
  60.     i++;
  61.    }
  62.    while(conf[j+1+i]!='\n');
  63.    port[i]='\0';
  64.    i=0;
  65.   }
  66.   if((conf[j]=='=') && (conf[j-1]=='g') && (conf[j-2]=='o') && (conf[j-3]=='l'))
  67.   {
  68.    do
  69.    {
  70.     logg[i]=conf[j+1+i];
  71.     i++;
  72.    }
  73.    while(conf[j+1+i]!='\n');
  74.    logg[i]='\0';
  75.    i=0;
  76.   }
  77.   if((conf[j]=='=') && (conf[j-1]=='t') && (conf[j-2]=='o') && (conf[j-3]=='o') && (conf[j-4]=='r'))
  78.   {
  79.    do
  80.    {
  81.     root[i]=conf[j+1+i];
  82.     i++;
  83.    }
  84.    while(conf[j+1+i]!='\n');
  85.    root[i]='\0';
  86.    i=0;
  87.   }
  88.   j++;
  89.  }
  90.  while(conf[j]!='\0');
  91. }
  92. heure();
  93. printf("Chemin des Sites web : %s\n", root);
  94. heure();
  95. printf("Chemin du fichier de log : %s\n", logg);
  96. heure();
  97. printf("Numéro du port : %s\n", port);
  98. }
  99. void ssighup(int sig_num)
  100. {
  101. heure();
  102. printf("Fin de l'application\n" );
  103. close(desc);
  104. ouvrir_conf();
  105. desc==socket(AF_INET,SOCK_STREAM,0);
  106.         // Structure Serveur
  107.         adresse.sin_family=AF_INET;
  108.         adresse.sin_addr.s_addr=INADDR_ANY;
  109.         adresse.sin_port=htons(atoi(port));
  110. // Attachement en local (bind)
  111.         if(bind(desc,(struct sockaddr *)&adresse,longueur)==-1)
  112.         {
  113.  heure();
  114.  perror("Erreur bind()" );
  115.  exit(1);
  116. }
  117. heure();
  118. printf("serveur attaché en local\n" );
  119.         // Ecoute
  120.         if(listen(desc,5)==-1)
  121.         {
  122.  heure();
  123.  perror("Erreur listen()" );
  124.  exit(1);
  125. }
  126. heure();
  127. printf("Serveur en écoute\n" );
  128. }
  129. int ouvrir(char* msgrc, int desc2)
  130. {
  131. int i=0, j=0;
  132. char result[256];
  133. char url[512];
  134. do
  135. {
  136.  if((msgrc[j]=='G') && (msgrc[j+1]=='E') && (msgrc[j+2]=='T') && (msgrc[j+3]==' '))
  137.  {
  138.   do
  139.   {
  140.    result[i]=msgrc[j+4+i];
  141.    i++;
  142.   }
  143.   while((msgrc[j+3+i]!=' ') && (msgrc[j+4+i]!='H') && (msgrc[j+5+i]!='T') && (msgrc[j+6+i]!='T') && (msgrc[j+7+i]!='P') && (msgrc[j+8+i]!='/'));
  144.   result[i]='\0';
  145.   i=0;
  146.  }
  147.  j++;
  148. }
  149. while(msgrc[j]!='\0');
  150. j=0;
  151. i=0;
  152. do
  153. {
  154.  url[i]=root[i];
  155.  i++;
  156. }
  157. while(root[i]!='\0');
  158. do
  159. {
  160.  url[i]=result[j];
  161.  i++;
  162.  j++;
  163. }
  164. while(result[j]!='\0');
  165. url[i]='\0';
  166. i=0;
  167. j=0;
  168. do
  169. {
  170.  i++;
  171. }
  172. while(url[i]!='\0');
  173. // printf("%s\n", url);
  174. i--;
  175. if(url[i]!='l' && url[i-1]!='m' && url[i-2]!='t' && url[i-3]!='h' && url[i-4]!='.')
  176. {
  177.  url[i+1]='/';
  178.  url[i+2]='i';
  179.  url[i+3]='n';
  180.  url[i+4]='d';
  181.  url[i+5]='e';
  182.  url[i+6]='x';
  183.  url[i+7]='.';
  184.  url[i+8]='h';
  185.  url[i+9]='t';
  186.  url[i+10]='m';
  187.  url[i+11]='l';
  188.  url[i+12]='\0';
  189. }
  190. if(url[i]=='/')
  191. {
  192.  url[i+1]='i';
  193.  url[i+2]='n';
  194.  url[i+3]='d';
  195.  url[i+4]='e';
  196.  url[i+5]='x';
  197.  url[i+6]='.';
  198.  url[i+7]='h';
  199.  url[i+8]='t';
  200.  url[i+9]='m';
  201.  url[i+10]='l';
  202.  url[i+11]='\0';
  203. }
  204. heure();
  205. printf("%s Page a affichée : %s\n", inet_ntoa(adresse.sin_addr.s_addr), url);
  206. int d;
  207. char c;
  208. int fp=0;
  209. char msgerror[1024] = "<h3>Erreur 404, Fichier ou Dossier non trouv&eacute;</h3>\0";;
  210. j=0;
  211. if ((d=open(url, O_RDONLY))==-1)
  212. {
  213. //  if(write(desc2,(void *)msgerror,strlen(msgerror),0,(struct sockaddr *)&adresse,sizeof(adresse))==0)
  214.  if(write(desc2,(void *)msgerror,strlen(msgerror))==0)
  215.  {
  216.   heure();
  217.   printf("%s ", inet_ntoa(adresse.sin_addr.s_addr));
  218.          perror("Erreur write() message d'erreur" );
  219.   memset(url, 0, sizeof(url));
  220.          exit(2);
  221.  }
  222.  return(1);
  223. }
  224. else
  225. {
  226.  if((d=open(url, O_RDONLY))!=-1)
  227.  {
  228.   while(read(d, &c, sizeof(char))!=0)
  229.   {
  230.    if (c!='\n')
  231.    {
  232.     html[j]=c;
  233.     j++;
  234.    }
  235.   }
  236.  }
  237.  close(d);
  238.  memset(url, 0, sizeof(url));
  239.  return(0);
  240. }
  241. }
  242. void *serverthread(desc2)
  243. {
  244. heure();
  245. printf("%s Thread lancé\n", inet_ntoa(adresse.sin_addr.s_addr));
  246. heure();
  247. printf("%s Lecture des informations emises par le client\n", inet_ntoa(adresse.sin_addr.s_addr));
  248. char msgrc[512];
  249. int opn;
  250. //      if(read(desc2,(void *)msgrc,512,0,(struct sockaddr *)&adresse,&longueur)==0)
  251.         if(read(desc2,(void *)msgrc,512)==0)
  252.         {
  253.  printf("%s ", inet_ntoa(adresse.sin_addr.s_addr));
  254.                 perror("Erreur read()" );
  255.                 exit(3);
  256.         }
  257. if((opn=ouvrir(msgrc, desc2))==0)
  258. {
  259. //         if(write(desc2,(void *)html,strlen(html),0,(struct sockaddr *)&adresse,sizeof(adresse))==0)
  260.         if(write(desc2,(void *)html,strlen(html))==0)
  261.         {
  262.   heure();
  263.   printf("%s ", inet_ntoa(adresse.sin_addr.s_addr));               
  264.   perror("Erreur write() affichage html" );
  265.                 exit(2);
  266.         }
  267.  memset(html, 0, sizeof(html));
  268. }
  269.         // emission
  270. heure();
  271. printf("%s Thread terminé\n", inet_ntoa(adresse.sin_addr.s_addr));
  272.         close(desc2);
  273. heure();
  274. printf("%s Connexion fermée\n", inet_ntoa(adresse.sin_addr.s_addr));
  275. pthread_exit((int *)tid);
  276. }
  277. int main()
  278. {
  279. ouvrir_conf();
  280. sigset_t  sigmask;
  281. struct sigaction  action, old_action;
  282. sigemptyset(&sigmask);
  283. action.sa_handler = ssighup;
  284. action.sa_flags = 0;
  285. if (sigaction(SIGINT,&action,&old_action)==-1)
  286. {
  287.  heure();
  288.  perror("Erreur sigaction()" );
  289.  exit(1);
  290. }
  291.      int desc2;
  292.         desc=socket(AF_INET,SOCK_STREAM,0);
  293.         // Structure Serveur
  294.         adresse.sin_family=AF_INET;
  295.         adresse.sin_addr.s_addr=INADDR_ANY;
  296.         adresse.sin_port=htons(atoi(port));
  297. // Attachement en local (bind)
  298.         if(bind(desc,(struct sockaddr *)&adresse,longueur)==-1)
  299.         {
  300.  heure();
  301.  perror("Erreur bind()" );
  302.  exit(1);
  303. }
  304. heure();
  305. printf("serveur attaché en local\n" );
  306.         // Ecoute
  307.         if(listen(desc,5)==-1)
  308.         {
  309.  heure();
  310.  perror("Erreur listen()" );
  311.  exit(1);
  312. }
  313. heure();
  314. printf("Serveur en écoute\n" );
  315.         while(1)
  316.         {
  317.                 if((desc2=accept(desc, (struct sockaddr *)&adresse, &longueur)) < 0)
  318.                 {
  319.   heure();
  320.                         perror("Erreur sur accept()" );
  321. //                        exit(1);
  322.                 }
  323.  heure();
  324.  printf("Connexion acceptée\n" );
  325.                 if(pthread_create(&tid, NULL, serverthread, (void *)desc2)!=0)
  326.                 {
  327.   heure();
  328.                         perror("Erreur sur pthread_create()" );
  329. //                        exit(1);
  330.                 }
  331.         }
  332.         pause();
  333.         return(0);
  334. }


 
Note : Il y a maintenant un fichier de configuration :

Citation :

# http.conf
#
# Fichier de configuration du serveur http
port=8080
log=monlog.log
root=/home/clement/web
 


 
Note :  
J'ai laissé tombé le nettoyage propre avec SIGINT
J'ai remplacé le SIGHUP par SIGTERM pour pouvoir tester beaucoup plus facilement
Il me reste juste à gérer que tous les affichages écrans s'affichent à la fois sur l'écran mais aussi dans le fichier de log, j'ai regardé la fonction dup2 (man dup2 + internet mais je ne l'ai pas bien comprise - par contre sigaction sans aucuns problèmes -)
 
Un dernier petit coup de pouce svp !
 
Merci encore !

Reply

Marsh Posté le 19-02-2008 à 12:47:35    

Ah non tu ne peux pas afficher à la fois sur l'écran et dans un fichier avec dup2. La seule solution c'est de te faire un fonction qui fait les deux printf.
 
Avec dup2 ce que tu peux faire c'est faire en sorte que STDERR (ou STDOU) pointe vers un fichier. Les affichages se font alors dans le fichier au lieu de se faire à l'écran.

Reply

Marsh Posté le 19-02-2008 à 14:27:19    

Pour l'affichage écran pas de problèmes, le printf je connais bien par contre comment écrire dans un fichier très simplement ? sans passer par une écriture caractère par caractère ?

Reply

Marsh Posté le 19-02-2008 à 16:11:51    

Et bien c'est pareil, tu ouvres un fichier avec fopen puis tu passes le FILE * à fprintf.

Reply

Marsh Posté le 25-02-2008 à 21:20:56    

Merci tout marche impecablement maintenant merci à tous !

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed