gSOAP is used to implement a simple server and proxy for four operations.
Table of Contents
Generate server and client (agent) programs
Try to use gSOAP to realize a simple server code of four operations, and give
Header file
Write the header file calc.h
//gsoap ns service name: calc Simple calculator service //gsoap ns service style: rpc //gsoap ns service encoding: encoded //gsoap ns service namespace: http://localhost/calc.wsdl //gsoap ns service location: http://localhost/server.cgi //gsoap ns schema namespace: urn:calc //gsoap ns service method: add Sums two values int ns__add(double a, double b, double *result); //gsoap ns service method: sub Subtracts two values int ns__sub(double a, double b, double *result); //gsoap ns service method: mul Multiplies two values int ns__mul(double a, double b, double *result); //gsoap ns service method: div Divides two values int ns__div(double a, double b, double *result); //gsoap ns service method: pow Raises a to b int ns__pow(double a, double b, double *result);
Note that "\\\\\" in NS add is double underlined.
Generate header file calc.h
You can also generate a header file through the wsdl 2H instruction by using a wsdl file, as follows:
How to use wsdl2h
wsdl 2H is used as the conversion of wsdl and. H files. soapcpp2 uses header files to generate h and cpp files needed for client / server development. Some frequently used instructions are as follows: - o filename.h converts the wsdl to a filename.h header file. - s does not generate STL code - C generates pure C-style header files, which will remove some features of C + + - N name use name instead of the default prefix ns - t filename.dat use filename.dat instead of the default typemap.dat file - zX compatible with previous versions of X
Generate server and client (agent) programs
Then the corresponding soap proxy code is generated by using the soapcpp2 instruction. The common options and usage of soapcpp2 are as follows:
How to use soapcpp2
wsdl 2H is used as the conversion of wsdl and. H files. soapcpp2 uses header files to generate h and cpp files needed for client / server development. Some frequently used instructions are as follows: - i generates the proxy and object of the server, which are inherited from the soap struct. - j is similar to - i, except that the generated proxy class does not inherit from soap struct, but contains a pointer containing a soap structure. Agent classes that live in this way are easy to communicate with each other - C generate client code only - S only generates server code - x does not generate an xml file. Without this, a descriptive xml file will be generated for each operation defined in the header file - L does not generate soapClientLib and soapServerLib files - p name changes the filename prefix instead of soap - q name specifies the namespace name used by proxy classes and objects, including the filename prefix
Can be passed separately
soapcpp2 -S -i calc.h
and
soapcpp2 -C -i calc.h
Generate the server and client (agent) programs soapcalcService.cpp, soapcalcProxy.cpp.
Complete makefile
HDR_CALC:=calc.h SRC_SERVER:=calcServer.cc SRC_CLIENT:=calcClient.cc SOAP_SRV:=soapC.cpp soapcalcService.cpp SOAP_CLT:=soapC.cpp soapcalcProxy.cpp LIBS:=-lgsoap++ all: server client #-i: generate C + + service agents and objects inherited from soap structure. ${SOAP_SRV}:${HDR_CALC} soapcpp2 -S -i ${HDR_CALC} ${SOAP_CLT}:${HDR_CALC} soapcpp2 -C -i ${HDR_CALC} client:${HDR_CALC} ${SOAP_CLT} g++ -o client ${SRC_CLIENT} ${SOAP_CLT} ${LIBS} server:${HDR_CALC} ${SOAP_SRV} g++ -o server ${SRC_SERVER} ${SOAP_SRV} ${LIBS} clean: rm -rf client server *.xml *.nsmap soap*
Client & server code
Server code calcServer.cc
#include "soapcalcService.h" #include "calc.nsmap" int main(int argc, char **argv) { calcService calc; if(argc < 2) { fprintf(stderr, "Usage: calcserver++ <port>\n"); exit(0); } if (argc < 2) calc.serve(); /* serve as CGI application */ else { int port = atoi(argv[1]); if (!port) { fprintf(stderr, "Usage: calcserver++ <port>\n"); exit(0); } /* run iterative server on port until fatal error */ if (calc.run(port)) { calc.soap_stream_fault(std::cerr); exit(-1); } } return 0; } int calcService::add(double a, double b, double *result) { *result = a + b; return SOAP_OK; } int calcService::sub(double a, double b, double *result) { *result = a - b; return SOAP_OK; } int calcService::mul(double a, double b, double *result) { *result = a * b; return SOAP_OK; } int calcService::div(double a, double b, double *result) { if (b) *result = a / b; else { char *s = (char*)soap_malloc(this, 1024); // (SOAP_SNPRINTF(s, 1024, 100), "<error xmlns=\"http://tempuri.org/\">Can't divide %f by %f</error>", a, b); snprintf(s, 1024, "<error xmlns=\"http://tempuri.org/\">Can't divide %f by %f</error>", a, b); return soap_senderfault("Division by zero", s); } return SOAP_OK; } int calcService::pow(double a, double b, double *result) { *result = ::pow(a, b); if (soap_errno == EDOM) /* soap_errno is like errno, but compatible with Win32 */ { char *s = (char*)soap_malloc(this, 1024); // (SOAP_SNPRINTF(s, 1024, 100), "<error xmlns=\"http://tempuri.org/\">Can't take power of %f to %f</error>", a, b); snprintf(s, 1024, "<error xmlns=\"http://tempuri.org/\">Can't take power of %f to %f</error>", a, b); return soap_senderfault("Power function domain error", s); } return SOAP_OK; }
Client code calcClient.cc
#include "soapcalcProxy.h" #include "calc.nsmap" char server[256] = "http://127.0.0.1:"; int main(int argc, char **argv) { if (argc < 5) { fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num port\n"); exit(0); } double a, b, result; a = strtod(argv[2], NULL); b = strtod(argv[3], NULL); calcProxy calc; strcat(server, argv[4]); calc.soap_endpoint = server; switch (*argv[1]) { case 'a': calc.add(a, b, &result); break; case 's': calc.sub(a, b, &result); break; case 'm': calc.mul(a, b, &result); break; case 'd': calc.div(a, b, &result); break; case 'p': calc.pow(a, b, &result); break; default: fprintf(stderr, "Unknown command\n"); exit(0); } if (calc.error) calc.soap_stream_fault(std::cerr); else printf("result = %g\n", result); return 0; }
Function
One terminal: $ ./server 121212 Another terminal: $ ./client add 123 234 121212 result = 357
Whole process