Appel d'url via un programme en C++

Appel d'url via un programme en C++ - C++ - Programmation

Marsh Posté le 25-10-2009 à 11:15:57    

Bonjour,
 
Je souhaite appeler depuis un programme en C++ une url sur un serveur web distant, par exemple http://www.monsite.com/maj.php?valeur=2
J'ai pensé à l'utilisation d'un socket pour pouvoir communiquer vers l'extérieur.
 
J'ai testé un bout de code trouvé sur le net afin de comprendre comment fonctionne un socket et j'avoue être un peu perdu, d'autant que j'ai juste une réaction en appelant google et uniquement au niveau de l'entête, bref j'ai besoin d'un petit coup de main !
 
Voici le source
 

Code :
  1. #ifndef _WINSOCKAPI_
  2. #include <winsock.h>
  3. #endif
  4. #include <stdafx.h>
  5. #include <windows.h>
  6. #include <stdio.h>
  7. #include <initguid.h>
  8. #include <errno.h>
  9. #include <signal.h>
  10. #include <tchar.h>
  11. #pragma comment(lib, "ws2_32.lib" )
  12. #define PACKET_SIZE  1024
  13. void bcopy( void * source, void * destination, int size )
  14. {
  15.    char * src = ( char * ) source;
  16.    char * dst = ( char * ) destination;
  17.    for( int i=0; i<size; i++ )
  18.       dst[i] = src[i];
  19. }
  20. void bzero( void * destination, int size )
  21. {
  22.    char * dst = ( char * ) destination;
  23.    for( int i=0; i<size; i++ )
  24.       dst[i] = 0x00;
  25. }
  26. void init(void);
  27. void appli();
  28. int writen(int fd, char *ptr, int n);
  29. int to_server_socket = -1;
  30. char server_name[100];         /* nom du host du serveur */
  31. int port;
  32. char request_host[PACKET_SIZE];
  33. char request_path[PACKET_SIZE];
  34. void main (int argc, char *argv[])
  35. {
  36. struct sockaddr_in serverSockAddr;    /* addresse de la socket */
  37. struct hostent *serverHostEnt;        /* description du host serveur */
  38. struct in_addr addr;
  39. long hostAddr;                       /* addr du serveur */
  40. WSADATA wsaData;
  41. WORD wVersionRequested;
  42. WSADATA wsa_data;
  43. int err = WSAStartup (MAKEWORD (2, 2), &wsa_data);
  44. if (!err)
  45. {
  46. /* if ( argc == 5 ) {
  47.    sprintf(server_name,argv[1]);
  48.    sscanf(argv[2],"%d",&port);
  49.    sprintf(request_host,argv[3]);
  50.    sprintf(request_path,argv[4]);
  51.    }
  52.   else
  53.    exit(1);
  54. */
  55.   sprintf(server_name,"localhost" );
  56.   sscanf("80","%d",&port);
  57.   sprintf(request_host,"http://www.google.fr" );
  58.   //sprintf(request_host,"209.85.227.106" );
  59.   sprintf(request_path,"/" );
  60.   printf("CONF %s %d %s %s\n",server_name,port,request_host,request_path);
  61.   wVersionRequested = MAKEWORD( 2, 2 );
  62.   err = WSAStartup( wVersionRequested, &wsaData );
  63.   if ( err != 0 ) {
  64.     printf("ca chie WSAStartup : %X\n",WSAGetLastError());
  65.     exit(1);
  66.   }
  67.      /* initialise a zero serverSockAddr */
  68.   bzero(&serverSockAddr,sizeof(serverSockAddr));
  69.      /* converti l'adresse ip 9.100.1.1 en entier long */
  70.   hostAddr = inet_addr(server_name);
  71.   if ( (long)hostAddr != (long)-1)
  72.       bcopy(&hostAddr,&serverSockAddr.sin_addr,sizeof(hostAddr));
  73.   else     /* si on a donne un nom  */
  74.   {
  75.       serverHostEnt = gethostbyname(server_name);
  76.       if (serverHostEnt == NULL)
  77.       {
  78.           printf("ca chie gethost : %X\n",WSAGetLastError());
  79.           exit(0);
  80.       }
  81.     printf("host_ip: " );
  82.     for(int i = 0; serverHostEnt->h_addr_list[i]; i++)
  83.     {
  84.         addr.s_addr = *(DWORD*) serverHostEnt->h_addr_list[i];
  85.         printf( "%s\t", inet_ntoa(addr));
  86.     }
  87.     printf("\n" );
  88.   bcopy(serverHostEnt->h_addr,
  89.             &serverSockAddr.sin_addr,serverHostEnt->h_length);
  90.   }
  91.   serverSockAddr.sin_port = htons(port);         /* host to network port  */
  92.   serverSockAddr.sin_family = AF_INET;            /* AF_*** : INET=internet */
  93.   serverSockAddr.sin_addr.s_addr = inet_addr("209.85.227.106" );
  94.   /* creation de la socket */
  95.   if ( (to_server_socket = socket(AF_INET,SOCK_STREAM,0)) < 0)
  96.   {
  97.       printf("ca chie creation socket client\n" );
  98.       exit(0);
  99.   }
  100.   /* requete de connexion */
  101.   if(connect(to_server_socket,(struct sockaddr *)&serverSockAddr,
  102.              sizeof(serverSockAddr))<0)
  103.   {
  104.       printf("ca chie demande de connection\n" );
  105.       exit(0);
  106.   }
  107.   appli();
  108.   /* fermeture de la connection */
  109.   shutdown(to_server_socket,2);
  110.   closesocket(to_server_socket);
  111.   WSACleanup( );
  112. }
  113. }
  114. int readn(int fd, char *ptr, int n);
  115. void appli (void) {
  116. char buffer[PACKET_SIZE+1];
  117. char line[PACKET_SIZE+2];
  118. int rc;
  119. int i = 0;
  120. static int isEntete = 1;
  121. char *finEntete;
  122. FILE *bulk, *entete;
  123.         sprintf(buffer,"Vide\n" );
  124.         sprintf(line,"GET %s HTTP/1.1\r\n"
  125.            "Host: %s\r\n"
  126. //           "Accept: image/gif, image/x-xbitmap, image/jpeg,"
  127. //           " image/pjpeg, image/png, */*"
  128.            "\r\n\r\n"
  129.            ,request_path,request_host);
  130.         if ( ( bulk = fopen("bulkhttp","wb" )) == NULL ) {
  131.                 printf ( "can't open file to write bulk\n" );
  132.                 exit(1);
  133.         }
  134.         if ( ( entete = fopen("entete","wb" )) == NULL ) {
  135.                 fclose(bulk);
  136.                 printf ( "can't open file to write entete\n" );
  137.                 exit(1);
  138.         }
  139.         send(to_server_socket,line,strlen(line)+1,0);
  140.         do {
  141.                 rc = readn(to_server_socket,buffer,PACKET_SIZE);
  142.                 if ( isEntete == 1 ) {
  143.                         finEntete = (char *)strstr(buffer,"\r\n\r\n" );
  144.                         if ( finEntete != NULL ) {
  145.                                 *finEntete = 0x00;
  146.                                 fwrite(buffer,1,strlen(buffer),entete);
  147.                                 fwrite(finEntete+4,1,rc-strlen(buffer)-4,bulk);
  148.                                 isEntete = 0;
  149.                         }
  150.                         else
  151.                                 fwrite(buffer,1,rc,bulk);
  152.                         fclose(entete);
  153.                 }
  154.                 else
  155.                         fwrite(buffer,1,rc,bulk);
  156.         } while ( rc != 0 ) ;
  157.         fclose(bulk);
  158. }
  159. int writen(int fd, char *ptr, int n)
  160. {
  161. int nl, nw;
  162.         nl = n;
  163.         while ( nl > 0 ) {
  164.                 nw = send(fd, ptr, nl,0);
  165.                 if ( nw <= 0 )
  166.                         return nw;     /*error*/
  167.                 nl -= nw;
  168.                 ptr += nw;
  169.         }
  170.         return (n-nl);
  171. }
  172. int readn(int fd, char *ptr, int n){
  173. int nl, nr;
  174.         nl = n;
  175.         while ( nl > 0 ) {
  176.                 nr = recv(fd,ptr,nl,0);
  177.                 if (nr < 0 )
  178.                         return nr;     /*error*/
  179.                 else
  180.                         if ( nr == 0 )
  181.                                 break;
  182.                 nl -= nr;
  183.                 ptr += nr;
  184.         }
  185. }


 
 
Si je ne force pas à la ligne 121 l'adresse ip, le nom n'est pas résolu et j'obtiens une erreur.
Mais même avec cette bidouille, seul le fichier entête généré est alimenté.
 
Voici le contenu du fichier d'entête :
 

Code :
  1. HTTP/1.1 302 Found
  2. Location: http://www.google.fr/
  3. Cache-Control: private
  4. Content-Type: text/html; charset=UTF-8
  5. Set-Cookie: PREF=ID=4861fc427cd617d0:TM=1256465687:LM=1256465687:S=v0S3inq215Ip8WMs; expires=Tue, 25-Oct-2011 10:14:47 GMT; path=/; domain=.google.com
  6. Set-Cookie: NID=28=BZTeQcdHXt9dsERJzLxy0-jz05dZs95-SmLtSLT-TxK1vWzZkTBOUcLSWZbfLW2QC8LKjcCpoiiOPTtU2A8-e8RZEGTr255JHHFFlHz8AmBpiTTY8MDVggeYoVd927R_; expires=Mon, 26-Apr-2010 10:14:47 GMT; path=/; domain=.google.com; HttpOnly
  7. Date: Sun, 25 Oct 2009 10:14:47 GMT
  8. Server: gws
  9. Content-Length: 218
  10. X-XSS-Protection: 0

Reply

Marsh Posté le 25-10-2009 à 11:15:57   

Reply

Marsh Posté le 25-10-2009 à 13:06:29    

Ca fonctionne maintenant, il suffit de :
 
Mettre en ligne 76 le domaine appelé, par exemple www.monsite.com
Mettre en ligne 78 la même chose, donc par exemple www.monsite.com
Mettre en ligne 80 la page appelée, par exemple /page.php
 
Il faut supprimer la ligne 121.
 
Après exécution la page est bien appelée, parfois le temps de réponse peut dépasser 1 seconde.
 
Ensuite, dans le fichier entête j'ai un résultat de ce type :
 

Code :
  1. HTTP/1.1 200 OK
  2. Date: Sun, 25 Oct 2009 12:06:43 GMT
  3. Server: Apache/2.2.X (OVH)
  4. X-Powered-By: PHP/5.2.10
  5. Vary: Accept-Encoding
  6. Transfer-Encoding: chunked
  7. Content-Type: text/html


Message édité par Furbby le 25-10-2009 à 13:07:29
Reply

Marsh Posté le 26-10-2009 à 19:22:49    

J'ai une question au sujet de la fonction recv.
J'ai un comportement différent entre la version debug et la release.
La debut fonctionne très bien mais la release part en boucle car le fonction recv (dans readn) retourne une valeur différente de 0 alors qu'elle devrait retourner 0.
 
Une fois alimenté, le buffer ne contient pas la même fin en debug qu'en release, c'est à cause de cela que la fonction tourne en boucle.
 
J'ai trouvé un topic http://www.eggheadcafe.com/softwar [...] -mode.aspx de quelqu'un qui a rencontré le même problème mais je ne comprends pas sa résolution.
 
Avez-vous une idée ?
 
Merci

Reply

Marsh Posté le 26-10-2009 à 19:36:39    

le buffer est une chaine pas un buffer d'octet , y'a u 0 terminal à copier. D'ou l'utilsiation de strcpy au lieu de memcpy.
et passer à Boost::Asio ca te dit pas plutot que de te palucher ce code infame ?


Message édité par Joel F le 26-10-2009 à 19:37:15
Reply

Marsh Posté le 26-10-2009 à 20:52:47    

En mode debug, tout est initialisé à 0, ça permet le plus souvent de trouver les soucis mémoires plus rapidement qu'en mode optimisé.
Dans ce dernier mode en revanche, il y a en mémoire... un peu n'importe quoi. Vu que rien n'est initialisé de façon automatique, si tu ne l'as pas fait alors le contenu de ta mémoire est indéterminé.
Voila pourquoi il y a une différence de comportement entre les deux modes de compilation.


Message édité par Elmoricq le 26-10-2009 à 20:53:49
Reply

Marsh Posté le 27-10-2009 à 09:37:19    

Merci pour votre retour.
 
Effectivement le code est loin d'être beau mais mon objectif premier était de rapidement valider la faisabilité.  
Je vais le réécrire maintenant.
 
Par contre passer à Boost::Asio (que je ne connais pas) n'est pas vraiment envisagé car cette portion de code doit s'intégrer dans un programme déjà existant avec ses propres librairies.


Message édité par Furbby le 27-10-2009 à 09:39:25
Reply

Sujets relatifs:

Leave a Replay

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