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 :
- l'identification des services
- la dématérialisation de l'information (soumission, réception)
Les caractéristiques du service web sont les suivantes (cf ce site) :
- accessibilité via le réseau
- interface publique (ensemble d'opérations) décrite en XML ; ses descriptions (fonctionnalités, comment l'invoquer et où le trouver ?) sont stockées dans un annuaire ;
- échange d'information en XML, ces messages sont transportés par des protocoles Internet (généralement HTTP, mais rien n'empêche d'utiliser d'autres protocoles de transfert tels : SMTP, FTP, ... )
- l'intégration d'application en implémentant des services Web produit des systèmes faiblement couplés, le demandeur du service ne connaît pas forcément le fournisseur.
- Ce dernier peut disparaître sans perturber l'application cliente qui trouvera un autre fournisseur en cherchant dans l'annuaire (UDDI).
WSDL (Web Services Description Language) est une grammaire XML permettant de décrire un service web.
Le WSDL sert à décrire :
- le protocole de communication (SOAP RPC ou SOAP orienté message)
- le format de messages requis pour communiquer avec ce service
- les méthodes que le client peut invoquer
- la localisation du service
Une description WSDL est un document XML qui commence par la balise et qui contient les balises suivantes :
- <binding> : définit le protocole à utiliser pour invoquer le service web
- <port> : spécifie l'emplacement actuel du service
- <service> : décrit un ensemble de points finaux du réseau
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.
<definitions name="HelloService"
targetNamespace="http://localhost/wsdl/HelloService.wsdl"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://localhost/wsdl/HelloService.wsdl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<message name="SayHelloRequest">
<part name="firstName" type="xsd:string"/>
</message>
<message name="SayHelloResponse">
<part name="greeting" type="xsd:string"/>
</message>
<portType name="Hello_PortType">
<operation name="sayHello">
<input message="tns:SayHelloRequest"/>
<output message="tns:SayHelloResponse"/>
</operation>
</portType>
<binding name="Hello_Binding" type="tns:Hello_PortType">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="sayHello">
<soap:operation soapAction="sayHello"/>
<input>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:examples:helloservice"
use="encoded"/>
</input>
<output>
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="urn:examples:helloservice"
use="encoded"/>
</output>
</operation>
</binding>
<service name="Hello_Service">
<documentation>WSDL File for HelloService</documentation>
<port binding="tns:Hello_Binding" name="Hello_Port">
<soap:address
location="http://localhost:8080/SayHello/" />
</port>
</service>
</definitions>
- la partie <message name="SayHelloRequest"> permet de définir les paramètres en entrée du service, dans le cas présent une chaine de caractères.
- la partie <message name="SayHelloResponse"> permet de définir les paramètres en sortie du service, on retournera une chaine de caractères.
- la partie <portType name="Hello_PortType"> fait le lien entre les paramètres en entrée et ceux en sortie et décrit le nom du service sayHello
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 :
#include "common/soapHello_USCOREBindingService.h"
#include "common/Hello_USCOREBinding.nsmap"
#include <cstdlib>
#include <iostream>
using namespace std;
// ==================================================================
// implementation of 'sayHello' method of service
// ==================================================================
int Hello_USCOREBindingService::sayHello(std::string firstName, /* input */
std::string &greeting /* output */) {
greeting = "Hello " + firstName;
return SOAP_OK;
}
// ==================================================================
// main function
// ==================================================================
int main(int argc, char **argv) {
// define service on server side
Hello_USCOREBindingService service;
// use first argument as service port, should be 8080
if (argc < 2) {
service.serve(); /* serve as CGI application */
} else {
int port = atoi(argv[1]);
if (!port) {
cerr << "Usage: server.exe <port>" << endl;
exit(EXIT_FAILURE);
}
/* run iterative server on port until fatal error */
if (service.run(port)) {
service.soap_stream_fault(std::cerr);
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}
#include "common/Hello_USCOREBinding.nsmap" // XML namespace mapping table (only needed once at the global level)
#include "common/soapHello_USCOREBindingProxy.h" // the proxy class, also #includes "soapH.h" and "soapStub.h"
#include <cstdlib>
// ==================================================================
// main function
// ==================================================================
int main() {
// define service on client side
Hello_USCOREBindingProxy service;
std::string name = "JM";
std::string greetings;
// call 'sayHello' method of web service
if (service.sayHello(name, greetings) == SOAP_OK) {
std::cout << "result = " << greetings << std::endl;
} else {
service.soap_stream_fault(std::cerr);
}
// delete data and release memory
service.destroy();
exit(EXIT_SUCCESS);
}
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