Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2171 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  Appel d'url via un programme en C++

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Appel d'url via un programme en C++

n°1935209
Furbby
Posté le 25-10-2009 à 11:15:57  profilanswer
 

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

mood
Publicité
Posté le 25-10-2009 à 11:15:57  profilanswer
 

n°1935227
Furbby
Posté le 25-10-2009 à 13:06:29  profilanswer
 

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
n°1935529
Furbby
Posté le 26-10-2009 à 19:22:49  profilanswer
 

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

n°1935532
Joel F
Real men use unique_ptr
Posté le 26-10-2009 à 19:36:39  profilanswer
 

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
n°1935547
Elmoricq
Modérateur
Posté le 26-10-2009 à 20:52:47  profilanswer
 

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
n°1935609
Furbby
Posté le 27-10-2009 à 09:37:19  profilanswer
 

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

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  Appel d'url via un programme en C++

 

Sujets relatifs
[C#] Delegate générique[C#] Classes génériques, réflexion
Un lanceur de programme prenant en compte un paramètrecomment créer un bouton pour lancer mon programme depuis Excel
Texte en couleur (console)[php/mysql] lancer un programme php en cas d'updates de MySql [resolu]
Aide pour un ProgrammeArguments en C
[C++][Gtkmm] Récupérer la ligne sélectionnée d'un TreeView[C#] Connexion server BO - Crystal Report
Plus de sujets relatifs à : Appel d'url via un programme en C++


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR