gsoap 远程调用举例
gsoap 远程调用举例
gsoap生成Web Service框架代码。这里通过gsoap官网**Example XML SOAP server ©和Example XML SOAP client ©**例子来实现sgoap生成框架,并实现远程调用。
gsoap官网例程:https://www.genivia.com/dev.html#server-c
1、SOAP服务器
将gsoap安装路径下的import
和custom
文件夹,stdsoap2.h
和stdsoap2.h
拷贝到需要生成文件的路径中。
利用wsdl2h
工具和wsdl文档来生成.h
服务接口。然后通过soapcpp2
工具和.h
文件生成底层代码和接口。
$ wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
$ soapcpp2 -S -L -x calc.h
最终生成服务器代码。这里需要用到的文件主要有soapC.c soapServer.c stdsoap2.c calcserver.c stdsoap2.h soapStub.h soapH.h
。calcserver.c
是我手动创建的,用来实现wsdl文档中的接口和主函数。
calcserver.c
文件主要内容如下,代码来自gsoap官网案例。代码稍微有点问题,明明是C的例子,里面却出现了C++代码,这里直接将C++代码全部注释掉,不适用pow
功能。
#include "calc.nsmap" // XML namespace mapping table (only needed once at the global level)
#include "soapH.h" // server stubs, serializers, etc.
int main()
{
struct soap *soap = soap_new1(SOAP_XML_INDENT);
soap_set_namespaces(&soap, namespaces);
if (!soap_valid_socket(soap_bind(soap, NULL, 8080, 10))) // port 8080 and small BACKLOG queue for iterative servers
exit(EXIT_FAILURE);
/* 阻塞在soap_accept处,当有远程调用产生时,接收远程调用并进行相应的处理。 */
while (soap_valid_socket(soap_accept(soap)))
{
printf("accept ok\r\n");
if (soap_serve(soap) != SOAP_OK)
break;
soap_destroy(soap); // delete deserialized C++ instances
soap_end(soap); // delete other managed data
}
soap_print_fault(soap, stderr);
soap_free(soap); // free the soap struct context data
}
/* 以下是关于wsdl接口的实现。当客户端对服务器进行远程调用时,将会调用以下对应的函数。 */
int ns2__add(struct soap *soap, double a, double b, double *result)
{
printf("ns2__add called\r\n");
/* 这里把加法改成乘法,证明我们的调用没有问题。 */
*result = a * b;
return SOAP_OK;
}
int ns2__sub(struct soap *soap, double a, double b, double *result)
{
*result = a - b;
return SOAP_OK;
}
int ns2__mul(struct soap *soap, double a, double b, double *result)
{
*result = a * b;
return SOAP_OK;
}
int ns2__div(struct soap *soap, double a, double b, double *result)
{
if (b == 0.0)
{
char *msg = (char*)soap_malloc(soap, 1024);
snprintf(msg, 1024, "Trying to divide %f by zero", a);
return soap_sender_fault(soap, msg, NULL);
}
*result = a / b;
return SOAP_OK;
}
int ns2__pow(struct soap *soap, double a, double b, double *result)
{
// *result = ::pow(a, b);
// // soap_errno is like errno, but compatible with Win32
// if (soap_errno == EDOM)
// {
// char *msg = (char*)soap_malloc(soap, 1024);
// snprintf(msg, 1024, "<error xmlns=\"http://tempuri.org/\">Can't take power of %f to %f</error>", a, b);
// return soap_sender_fault(soap, "Power function domain error", s);
// }
return SOAP_OK;
}
完成calcserver.c
后,编译server并运行。我这里是通过wsl编译运行的。
$ gcc soapC.c soapServer.c stdsoap2.c calcserver.c -o calcserver
$ ./calcserver
这时服务器的ip使我们的本机IP:192.168.x.x,然后端口号是上面设置的8080。服务器已经搭建完成了,接下来进行client端开发,来访问我们的服务器。
2、SOAP客户端
Client操作流程和Server类似。同样的操作步骤,修改命令参数即可。这里将Client代码路径修改一下,不要和Server放在同一路径下,因为生成的soapStub.h
有略微差异,后面不方便同时修改客户端服务端代码。
根据gsoap官网的教程,生成代码。操作如下:
$ wsdl2h -c -o calc.h http://www.genivia.com/calc.wsdl
$ soapcpp2 -CL -x calc.h
最终生成客户端代码。这里需要用到的文件主要有soapC.c soapClient.c stdsoap2.c calcclient.c stdsoap2.h soapStub.h soapH.h
。calcClient.c
是我手动创建的,用来实现main函数对Server进行访问调用。
calcserver.c
文件主要内容如下,代码来自gsoap官网案例。这里对ns2__add进行远程调用,发送调用信息给服务器,服务器收到调用信息再调用具体实现函数。因为之前已经修改过add了,所以这里调用以后应该是乘法结构。
#include "calc.nsmap" // XML namespace mapping table (only needed once at the global level)
#include "soapH.h" // client stubs, serializers, etc.
int main()
{
struct soap *soap = soap_new(); // allocate and initialize a context
double sum;
soap->connect_timeout = 10; // connect within 10s
soap->send_timeout = 5; // send timeout is 5s
soap->recv_timeout = 5; // receive timeout is 5s
soap->socket_flags = MSG_NOSIGNAL;
if (soap_call_ns2__add(soap, NULL, NULL, 1.23, 4.56, &sum) == SOAP_OK)
printf("Sum = %g\n", sum);
else
soap_print_fault(soap, stderr);
soap_destroy(soap); // delete managed deserialized C++ instances
soap_end(soap); // delete other managed data
soap_free(soap); // free the soap struct context data
}
它这里的给的例子不是调用我们自己服务器的,所以需要将它调用的链接修改我们自己服务器的地址和端口号。在soapClient.c
中,对相应的代码进行修改,soap_endpoint
是用来控制访问地址的,这里修改成我们服务器的。
SOAP_FMAC5 int SOAP_FMAC6 soap_send_ns2__add(struct soap *soap, const char *soap_endpoint, const char *soap_action, double a, double b)
{ struct ns2__add soap_tmp_ns2__add;
if (soap_endpoint == NULL)
// soap_endpoint = "http://websrv.cs.fsu.edu/~engelen/calcserver.cgi";
soap_endpoint = "192.168.x.x:8080";
完成calcclient.c
后,编译client并运行。我这里是通过wsl编译运行的。
$ gcc soapC.c calcclient.c soapClient.c stdsoap2.c -o calcclient
$ ./calcclient
输出结果如下:
3、总结
以上就是利用gsoap工具通过wsdl文档来生成web service框架,我们只需要完成wsdl文档的接口就行了。