« Ubuntu | Samedi - Balade » |
SOAP with C/C++ & PHP
For my work, I need to create a client/server interface. The client must be programmed with C/C++ and the server with PHP.
After a quick look on the web, I found two projects of a SOAP C++ library which match with my requirement :
- Easysoap - http://easysoap.sourceforge.net/
- Axis - http://ws.apache.org/axis/index.html
- Gsoap - http://www.cs.fsu.edu/~engelen/soap.html
The main problem with the first one is the lake of maintenance of the project. Maybe there is no bug in it but the "last modification 12-April-2002" scared me a bit.
Despite the excellent reputation of apache's projects, I won't Axis because the requierement of having a webserver (apache) already installed on his computer (which is my case but not everybody).
For PHP, there is no standard version for PHP 4. There is one by default in PHP 5, but I am not ready to switch to this version (I know that I will have the envy to adapt my development with the object model that PHP 5 proposes).
One of the reference for PHP4 is :
- Nusoap - http://dietrich.ganx4.com/nusoap/index.php which has been developed using PHP (one file of 224 ko ...)
The PHP server
It is quite simple.
Download the nusoap program.
Create a php file located on your webserver :
<?php function encrypt($myString) { return md5("salt".md5($myString)); } require('nusoap.php'); $server = new soap_server(); $server->configureWSDL('security', 'urn:secure'); // Name of the server & the namespace in order to create the wsdl doc $server->register("encrypt", // method name array('symbol' => 'xsd:string'), // input parameters array('return' => 'xsd:string'), // output parameters 'urn:secure', // namespace 'urn:secure#encrypt'); // SOAP action $HTTP_RAW_POST_DATA = isset($HTTP_RAW_POST_DATA) ? $HTTP_RAW_POST_DATA : ''; $server->service($HTTP_RAW_POST_DATA); ?>
I declare the datatype of each variable to avoid mistake about datatypes.
The C client
/path/to/gsoap-linux-2.7/wsdl2h -c -o encrypt.h http://localhost/soap.php?wsdl
The -c option is used to force the generation in C.
This command creates the include thanks to the wsdl declaration.
In this file, we can find what we declared on the server (C++ style) :
int ns1__encrypt(
std::string symbol,
std::string &return_ // < response parameter
);
If you use C++, you will need the stlvector.h file in your current directory.
/path/to/gsoap-linux-2.7/soapcpp2 -c encrypt.h
Will generate the skeletons, xml sample of the flux ...
List of the files :
soapStub.h | header file with data type annotations |
soapH.h | header file of soapC.cpp |
soapC.c | SOAP/XML (de)serializers for C/C++ data types |
soapClient.c | proxy stub routines for remote method calls |
soapServer.c | skeleton routines for service implementation |
securityBinding.nsmap | a namespace mapping table for the client application |
securityBinding.encrypt.req.xml | xml sample of the request |
securityBinding.encrypt.res.xml | xml sample of the response |
encrypt.h | the header file declarations |
soapsecurityBindingObject.h | Proxy class (ie C++) for the service |
soapsecurityBindingProxy.h | Proxy class (ie C++) for the client |
soapClientLib.c | |
soapServerLib.c |
Create a encryptclient.c file :
#include "soapH.h" // obtain the generated stub #include "securityBinding.nsmap" // obtain the namespace mapping table #include "stdio.h" int main() { struct soap soap; // gSOAP runtime environment soap_init(&soap); // initialize runtime environment (only once) char *myVar="sandra"; char *result; if (soap_call_ns1__encrypt(&soap, NULL, NULL, myVar , &result) == SOAP_OK) printf("Key encrypted = %s ",result); else soap_print_fault(&soap, stderr); // display the SOAP fault message on the stderr stream soap_end(&soap); // remove deserialized data and clean up soap_done(&soap); // detach the gSOAP environment return (0); }
To compile this wonderful application :
gcc -g -I/path/to/gsoap-linux-2.7 -Wall -o encryptclient encryptclient.c soapC.c soapClient.c /path/togsoap-linux-2.7/stdsoap2.c
The processus for a C++ application is almost the same except that you don't have to use the -c parameter when saopcpp2 and wsdl2h are called.
Generated files will have an other extension (cpp instead of c) and include an proxy (basically a wrapper to use the soap web service).
There is the C++ solution without the proxy :
#include "soapH.h" // obtain the generated stub #include "securityBinding.nsmap" // obtain the namespace mapping table #include <iostream> #include <string> using namespace std; int main() { struct soap soap; // gSOAP runtime environment soap_init(&soap); // initialize runtime environment (only once) std::string myVar="sandra"; std::string result; if (soap_call_ns1__encrypt(&soap, NULL, NULL, myVar , result) == SOAP_OK) cout << "Key encrypted = " << result; else soap_print_fault(&soap, stderr); // display the SOAP fault message on the stderr stream soap_destroy(&soap); // delete deserialized class instances (for C++ only) soap_end(&soap); // remove deserialized data and clean up soap_done(&soap); // detach the gSOAP environment }
With the proxy (smaller & cleaner isn't it ?) :
#include "soapsecurityBindingProxy.h" /* get the gSOAP-generated proxy */ #include "securityBinding.nsmap" /* get service namespace bindings */ int main() { securityBinding sec; string result; if (sec.ns1__encrypt(string("sandra"), result) == SOAP_OK) cout << "Key encrypted = " << result; else soap_print_fault(sec.soap, stderr); }
For both sources, the compilation command is :
g++ -I/path/to/license/gsoap-linux-2.7 -Wall -o encryptclient encryptclient.cpp soapC.cpp soapClient.cpp /path/to/gsoap-linux-2.7/stdsoap2.cpp
If you want to use SSL (without prior authentication), just add this
if (soap_ssl_client_context(&soap,SOAP_SSL_NO_AUTHENTICATION,NULL,NULL,NULL,NULL,NULL)) { soap_print_fault(&soap, stderr); exit(1); }
and change the URL (https instead of http) in soapClient.{c/cpp]
URL = "https://localhost/soap.php";
And add :
-DWITH_OPENSSL -lssl -lcrypto
to gcc/g++.
Bonus - The client in Python with SOAPpy - http://pywebsvcs.sourceforge.net/ :
#!/usr/bin/python import SOAPpy try: server = SOAPpy.SOAPProxy("http://localhost:80/soap.php") print server.encrypt("sandra") except Exception, e: print """Error : %s """% e
Sources :
Tutorial - Nusoap with PHP4 : http://codewalkers.com/tutorials/74/4.html
gSOAP User Guide : http://www.cs.fsu.edu/~engelen/soapdoc2.html
Creating a C/C++ client for a WebSphere Web service using WebSphere Studio Application Developer, gSOAP, and Dev-C++ : http://www-900.ibm.com/developerWorks/cn/wsdd/library/techarticles/0301_lin/lin_eng.shtml
2 commentaires

Salut,
Je m’applelle Olivier BIGIRIMANA,je suis burundais (BURUNDI)et j’ai 22ans.J’aime beaucoup l’AUSTRALIE et j’aimeriais des amies en AUSTRALIE.Ecrivez-moi s.v.p.

moi c’est l’inverse le serveur doit etre en C pur. c’est pour un systeme embarqué. mais pour la compilation j’ai du mal je vais tenter une compil avec tes parametres.