Chapter 5. Make a SOAP client with C/C++ and gSOAP.
Table of Contents
5.1. gSOAP client for my JWSDP web service.
5.1.1. Consume a simple remote procedure with gSOAP.
5.1.2. Consume a remote procedure returning a complex type with gSOAP.
5.1.3. Handling arrays returned by a SOAP method with gSOAP.
5.2. Consume a .NET web service with gSOAP.
A chapter for the linux C/C++ developer (the tool works also fine under Windows;)! You will find here how to make simple and advanced SOAP client for JWSDP and .NET web service using gSOAP.
5.1. gSOAP client for my JWSDP web service.
First, you have to install the gSOAP library, see gSOAP at sourceforge. Download the package and follow the instruction in the readme file (tar -xvzf packagename.tar.gz to uncompress).
Once the package is installed, you can start to use the library to create (in our case) the C header file using wsdl2h. This tool (the gSOAP WSDL parser) will use my WSDL to create our header (rcx.h). This header will then be processed by soapcpp2 (the gSOAP compiler) to generate the stub for our client. And after we will have a green light to create our first gSOAP client. Follow me...
We begin by a first run of the gSOAP WSDL parser (check on my home page if my web service is on-line, using the link at the bottom of this page):
[your_prompt]$ wsdl2h -c -o rcx.h http://www.pascalbotte.be/rcx-ws-rpc/rcx?WSDL
We will have to execute the tool a second time after customization of the name of the namespaces prefix automatically generated by wsdl2h. So add the necessary lines (see the comment in the rcx.h file) to typemap.dat and run, once again, the same command.
That's it, you are now ready to call the gSOAP compiler (soapcpp2):
[your_prompt]$ soapcpp2 -c rcx.h
![]() | Pure C code |
---|---|
The -c is used to generate pure C code. You can omit it, but you will need the stlvector.h in your current directory to compile your C++ client. |
Take a look at the file generated, we will directly include RcxReadLSBinding.nsmap and soapH.h in our C client.
See next section how to create the client using the stub generated.
5.1.1. Consume a simple remote procedure with gSOAP.
In this section I will show how to consume the readTemp() remote procedure. This fonction takes a param of type int and returns a float.
Example 5-1. A simple gSOAP client.
#include "stdio.h" #include "soapH.h" #include "RcxReadLSBinding.nsmap" int main() { struct soap soap; //expected temperature returned //by my web service float temp; soap_init(&soap); //you will find in the soapClient.c file //the prototype of the remote procedure //you want to consume (in bold below) if(soap_call_ns1__readTemp(&soap, NULL /*endpoint address*/, NULL /*soapAction*/, 1 /*fixed value needed for my remote procedure*/, &temp /*temperature returned*/ )== SOAP_OK) printf("temperature: %f\n",temp); else soap_print_fault(&soap, stderr); soap_destroy(&soap); soap_end(&soap); soap_done(&soap); return 0; }
Once this is done, it is time to compile. Here I will use g++.
[your_prompt]$ g++ -I/your_path_to/gsoap-2.7 -o client.o client.c soapC.c soapClient.c /your_path_to/gsoap-2.7/soapcpp2/stdsoap2.c
A little chmod, so you can execute your client.
[your_prompt]$ chmod a+x client.o
Take a look at my home page (you have a link at the bottom of this page) and check if my web service is on-line. If yes, you can test your client.
[your_prompt]$ ./client.o
Congratulation, this look like to be your first SOAP client in C with gSOAP?? Yes/No? (for me it was!) OK, next section we will try to consume my status() remote procedure to test a complex return type.
5.1.2. Consume a remote procedure returning a complex type with gSOAP.
To consume my status() function we can completely rely on the classes generated by gSOAP. And the call is almost as simple as for the preceding simple type call.
Add the following lines to your client to call the status() remote procedure. As usually you will find the function declaration in the soapClient.c file. The declaration for the ns1__statusResponse structure will be found in the rcx.h file.
stuct ns1__statusResponse ns1stresp; if(soap_call_ns1__status(&soap, NULL/*endpoint*/, NULL/*soapAction*/, &ns1stresp)== SOAP_OK) printf("rcxResponse object:\n\tmessage: %s\ \n\tbattery: %f\ \n\tmemory: %d\ \n\tcurrent time: %d\n", ns1stresp._result->status, ns1stresp._result->battery, ns1stresp._result->memory, ns1stresp._result->currentTime ); else soap_print_fault(&soap, stderr);
In the next section you will find examples consuming arrays of simple and complex type.
5.1.3. Handling arrays returned by a SOAP method with gSOAP.
Once again, this library is very easy and simple to use. We see here a great tool hiding completely the complexity of SOAP message transmitting (arrays of) complex type. See the code to add to our client to consume my collInt() and collPos() remote procedure, returning respectively an array of type int and of type PosCol. The PosCol object contains two integer value: XPos and YPos.
//these structs are defined in rcx.h struct ns1__collIntResponse ns1ciresp; struct ns1__collPosResponse ns1cpresp; //you will find the methods in bold in soapClient.c if(soap_call_ns1__collInt(&soap, NULL/*endpoint*/, NULL/*soapAction*/, &ns1ciresp)== SOAP_OK) { printf("Array of int size: %d\n",ns1ciresp._result->__size); for(int x=0; x < ns1ciresp._result->__size; x++) printf("\telement %d: %d\n", x, ns1ciresp._result->__ptr[x]); } else soap_print_fault(&soap, stderr); if(soap_call_ns1__collPos(&soap, NULL/*endpoint*/, NULL/*soapAction*/, &ns1cpresp)== SOAP_OK) { printf("PosCol array size: %d\n",ns1cpresp._result->__size); for(int x=0; x < ns1cpresp._result->__size; x++) printf("\tPosCol element %d: XPos = %d, YPos = %d\n",x, ns1cpresp._result->__ptr[x]->XPos, ns1cpresp._result->__ptr[x]->YPos ); } else soap_print_fault(&soap, stderr);
Next page we will create a more advanced gSOAP client by consuming the Infobel .NET web service.