3. C++ et le monde extérieur



sommaire chapitre 3

3.9. Web Services et GSOAP

Qu'est ce qu'un service web ?

On peut définir un service web (web service en anglais) comme une technologie permettant à des applications de dialoguer à distance via Internet indépendamment des plates-formes et des langages sur lesquels elles reposent.

L'usage de XML pour la description du service et l'échange de données permet de « simplifier » la compatibilité et l'interopérabilité lors de la conception puis lors de l'utilisation. XML permet de rendre le service web indépendants des plates-formes (Système d'exploitation, langage).

Les problèmes liés aux web services concernent :

Les caractéristiques du service web sont les suivantes (cf ce site) :

WSDL (Web Services Description Language) est une grammaire XML permettant de décrire un service web.

Le WSDL sert à décrire :

Une description WSDL est un document XML qui commence par la balise et qui contient les balises suivantes :

3.9.1. GSOAP

GSOAP est une implémentation C++ pour les services web SOAP et REST.

The gSOAP toolkit is a C and C++ software development toolkit for SOAP and REST XML Web services and generic C/C++ XML data bindings.

The toolkit analyzes WSDLs and XML schemas (separately or as a combined set) and maps the XML schema types and the SOAP/REST XML messaging protocols to easy-to-use and efficient C and C++ code.

It also supports exposing (legacy) C and C++ applications as XML Web services by auto-generating XML serialization code and WSDL specifications. Or you can simply use it to automatically convert XML to/from C and C++ data. The toolkit supports options to generate pure ANSI C or C++ with or without STL.

On pourra retrouver la documentation officielle de GSOAP sur le site suivant Getting started with GSOAP.

3.9.2. Installation de GSOAP

Avant de commencer l'installation s'assurer que la librairie libssl-dev a été installée :

sudo apt-get install libssl-dev

Télécharger gsoap par exemple la version gsoap_2.8.22.zip

\$ sudo su
\$ cp gsoap_2.8.22.zip /opt
\$ unzip gsoap_2.8.22.zip
\$ cd gsoap-2.8  

\$ ./configure
\$ make
\$ make install

....

+--------------------------------------------------------+
| You now have successfully built and installed gsoap.   |
|                                                        |
| You can link your programs with -lgsoap++ for          |
| C++ projects created with soapcpp2 and you can link    |
| with -lgsoap for C projects generated with soapcpp2 -c |
|                                                        |
| There are also corresponding libraries for SSL and     |
| zlib compression support (-lgsoapssl and lgsoapssl++)  |
| which require linking -lssl -lcrypto -lz               |
|                                                        |
| Thanks for using gsoap.                                |
|                                                        |
|               http://sourceforge.net/projects/gsoap2   |
+--------------------------------------------------------+

3.9.3. Création d'un serveur et d'un client GSOAP

On désire créer un service très simple qui consiste à lui envoyer le nom d'une <personne>, le service retournera le message "Hello <personne>". Le service sera installé en local sur la machine sur le port 8080.

Les sources peuvent être téléchargées à cette adresse.

On retrouvera le même principe que pour le RMI (Remote Method Invocation) (cf cours M1 Informatique.

On part de la définition du service web au format WSDL.

  1. <definitions name="HelloService"
  2.   targetNamespace="http://localhost/wsdl/HelloService.wsdl"
  3.   xmlns="http://schemas.xmlsoap.org/wsdl/"
  4.   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  5.   xmlns:tns="http://localhost/wsdl/HelloService.wsdl"
  6.   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  7.  
  8.    <message name="SayHelloRequest">
  9.       <part name="firstName" type="xsd:string"/>
  10.    </message>
  11.    
  12.    <message name="SayHelloResponse">
  13.       <part name="greeting" type="xsd:string"/>
  14.    </message>
  15.  
  16.    <portType name="Hello_PortType">
  17.       <operation name="sayHello">
  18.          <input message="tns:SayHelloRequest"/>
  19.          <output message="tns:SayHelloResponse"/>
  20.       </operation>
  21.    </portType>
  22.  
  23.   <binding name="Hello_Binding" type="tns:Hello_PortType">
  24.       <soap:binding style="rpc"
  25.         transport="http://schemas.xmlsoap.org/soap/http"/>
  26.       <operation name="sayHello">
  27.          <soap:operation soapAction="sayHello"/>
  28.          <input>
  29.             <soap:body
  30.               encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  31.               namespace="urn:examples:helloservice"
  32.               use="encoded"/>
  33.          </input>
  34.        
  35.          <output>
  36.             <soap:body
  37.               encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  38.               namespace="urn:examples:helloservice"
  39.               use="encoded"/>
  40.          </output>
  41.       </operation>
  42.    </binding>
  43.  
  44.    <service name="Hello_Service">
  45.       <documentation>WSDL File for HelloService</documentation>
  46.       <port binding="tns:Hello_Binding" name="Hello_Port">
  47.          <soap:address
  48.            location="http://localhost:8080/SayHello/" />
  49.       </port>
  50.    </service>
  51. </definitions>
  52.  

Lancer la compilation du projet avec le makefile ce qui permet de générer la partie client ainsi que la partie serveur et les fichiers communs. L'organisation des répertoires est la suivante :


.
├── bin
├── HelloService.wsdl
├── makefile
└── src
    ├── client
    │   └── client.cpp
    ├── common
    └── server
        └── server.cpp

Le répertoire src/common contiendra l'ensemble des fichiers générés par gsoap.

wsdl2h -o src/common/hello_service.h HelloService.wsdl
# generate client
soapcpp2 -i -C -dsrc/common src/common/hello_service.h
# generate server
soapcpp2 -i -S -dsrc/common src/common/hello_service.h

Il faut alors créer un fichier pour lancer le serveur et un pour lancer le client :

  1. #include "common/soapHello_USCOREBindingService.h"
  2. #include "common/Hello_USCOREBinding.nsmap"
  3. #include <cstdlib>
  4. #include <iostream>
  5. using namespace std;
  6.  
  7. // ==================================================================
  8. // implementation of 'sayHello' method of service
  9. // ==================================================================
  10. int Hello_USCOREBindingService::sayHello(std::string firstName, /* input */
  11.     std::string &greeting /* output */) {
  12.    
  13.     greeting = "Hello " + firstName;
  14.     return SOAP_OK;
  15. }
  16.  
  17. // ==================================================================
  18. // main function
  19. // ==================================================================
  20. int main(int argc, char **argv) {
  21.     // define service on server side
  22.     Hello_USCOREBindingService service;
  23.    
  24.     // use first argument as service port, should be 8080
  25.     if (argc < 2) {
  26.         service.serve();       /* serve as CGI application */
  27.     } else {
  28.         int port = atoi(argv[1]);
  29.         if (!port) {
  30.             cerr << "Usage: server.exe <port>" << endl;
  31.             exit(EXIT_FAILURE);
  32.         }
  33.        
  34.         /* run iterative server on port until fatal error */
  35.         if (service.run(port)) {
  36.             service.soap_stream_fault(std::cerr);
  37.             exit(EXIT_FAILURE);
  38.         }
  39.     }
  40.  
  41.     return EXIT_SUCCESS;
  42. }
  43.  
  44.  
  45.  
  1. #include "common/Hello_USCOREBinding.nsmap"      // XML namespace mapping table (only needed once at the global level)
  2. #include "common/soapHello_USCOREBindingProxy.h" // the proxy class, also #includes "soapH.h" and "soapStub.h"
  3. #include <cstdlib>
  4.  
  5. // ==================================================================
  6. // main function
  7. // ==================================================================
  8. int main() {
  9.     // define service on client side
  10.     Hello_USCOREBindingProxy service;
  11.  
  12.     std::string name = "JM";
  13.     std::string greetings;
  14.    
  15.     // call 'sayHello' method of web service
  16.     if (service.sayHello(name, greetings) == SOAP_OK) {
  17.         std::cout << "result  = " << greetings << std::endl;
  18.     } else {
  19.         service.soap_stream_fault(std::cerr);
  20.     }
  21.    
  22.     // delete data and release memory
  23.     service.destroy();
  24.    
  25.     exit(EXIT_SUCCESS);
  26. }
  27.  

3.9.4. Test de l'application

Dans un premier terminal lancer le serveur :

./bin/server.exe 8080

Dans un autre terminal lancer le client :

./bin/client.exe
result  = Hello JM