用gSOAP实现一个简单四则运算的服务器及代理。
Table of Contents
试着用gSOAP实现一个简单四则运算的服务器代码,给出
头文件
编写头文件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);
注意ns__add中的“__”为双下划线。
生成头文件calc.h
也可通过使用wsdl文件通过wsdl2h指令生成头文件,如下:
wsdl2h使用方法
wsdl2h用作wsdl和.h文件的转换。soapcpp2用头文件生成客户端/服务端等开发需要的h和cpp文件。
经常使用的一些指令如下:
-o filename.h 将wsdl转化为filename.h头文件。
-s 不生成STL代码
-c 生成纯C风格的头文件,这将去除C++的一些特性
-n name 使用name代替默认前缀ns
-t filename.dat 使用filename.dat代替默认的typemap.dat文件
-zX 兼容之前的X版本
生成服务端和客户端(代理)程序
然后通过使用soapcpp2指令生成对应的soap代理代码,soapcpp2的常用选项和使用方法如下:
soapcpp2使用方法
wsdl2h用作wsdl和.h文件的转换。soapcpp2用头文件生成客户端/服务端等开发需要的h和cpp文件。
经常使用的一些指令如下:
-i 生成server的proxy和object,这种object继承于soap struct。
-j 和-i类似,区别在于生成的代理类不继承于soap struct,而是包含了包含了一个soap结构的指针。此种方式生存的代理类便于互相通信
-C 仅生成客户端client代码
-S 仅生成服务端server代码
-x 不生成xml文件。不用此项的话,将对头文件中定义的每个operation生成一个描述性的xml文件
-L 不生成soapClientLib文件和soapServerLib文件
-p name 修改文件名前缀,代替soap
-q name 指定代理类和对象使用的名空间name,包含文件名前缀
可以分别通过
soapcpp2 -S -i calc.h
和
soapcpp2 -C -i calc.h
生成服务端和客户端(代理)程序soapcalcService.cpp,soapcalcProxy.cpp。
完整的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 : 生成从soap结构继承的C ++服务代理和对象。
${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*
客户端&服务端代码
服务端代码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;
}
客户端代码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;
}
运行
一个终端:
$ ./server 121212
另一个终端:
$ ./client add 123 234 121212
result = 357
整体流程