分类: C/C++
2007-10-13 11:56:13
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 -
- Axis -
- Gsoap -
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 - which has been developed using PHP (one file of 224 ko ...)
[Suite:]
The PHP server
It is quite simple.
Download the nusoap program.
Create a php file located on your webserver :
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
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
#include
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 = "";
And add :
-DWITH_OPENSSL -lssl -lcrypto
to gcc/g++.
Bonus - The client in Python with SOAPpy - :
#!/usr/bin/pythonSources :
import SOAPpy
try:
server = SOAPpy.SOAPProxy("")
print server.encrypt("sandra")
except Exception, e:
print """Error : %s """% e
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1329786