gSOAP基于头文件的webservice过程
一 服务端
1 打开VS2005,创建一个工程,命名为calcServer。
2 添加一个头文件calc.h,编辑内容如下:
1//gsoap ns service name: calc 2//gsoap ns service port: http://localhost/calc.wsdl 3//gsoap ns service location: http://localhost 4//gsoap ns service executable: calc.cgi 5//gsoap ns service encoding: encoded 6//gsoap ns service type: calcPortType
7//gsoap ns schema namespace: urn:add
//gsoap ns service method-documentation: add Sums two values int ns__add(double a,double b, double *result);
//gsoap ns service method-documentation: sub Subtracts two values int ns__sub(double a,double b, double *result);
//gsoap ns service method-documentation: mul Multiplies two values int ns__mul(double a,double b, double *result);
//gsoap ns service method-documentation: div Divides two values int ns__div(double a,double b, double *result);
//gsoap ns service method-documentation: pow Raises a to b int ns__pow(double a,double b, double *result);
|
说明:
1) 前面的1-7行在生成的XML文件里会有所体现。
2)第一行定义了服务名,如果第一行写成“//gsoapns service name: calc1”,编译时则将“calc1”当作服务名称,生成的文件中也会使用这个名称。
D:\gSOAP_study\gSOAP_test_calc\calc_server>soapcpp2.exe -c -e calc.h
** The gSOAP code generator for C and C++, soapcpp2 release 2.8.15 ** Copyright (C) 2000-2013, Robert van Engelen, Genivia Inc. ** All Rights Reserved. This product is provided "as is", without any warranty. ** The soapcpp2 tool is released under one of the following two licenses: ** GPL or the commercial license by Genivia Inc.
Saving soapStub.h annotated copy of the source input Saving soapH.h interface declarations Using ns service name: calc1 Using ns service encoding: encoded Using ns service location: http://localhost/calc.wsdl http://localhost Using ns service executable: calc.cgi Using ns schema namespace: urn:add Saving calc1.wsdl Web Service description Saving calc1.add.req.xml sample SOAP/XML request Saving calc1.add.res.xml sample SOAP/XML response Saving calc1.sub.req.xml sample SOAP/XML request Saving calc1.sub.res.xml sample SOAP/XML response Saving calc1.mul.req.xml sample SOAP/XML request Saving calc1.mul.res.xml sample SOAP/XML response Saving calc1.div.req.xml sample SOAP/XML request Saving calc1.div.res.xml sample SOAP/XML response Saving calc1.pow.req.xml sample SOAP/XML request Saving calc1.pow.res.xml sample SOAP/XML response Saving calc1.nsmap namespace mapping table Saving ns.xsd XML schema Saving soapClient.c client calling stubs Saving soapClientLib.c client stubs with serializers (use only for libs) Saving soapServer.c server request dispatcher Saving soapServerLib.c server request dispatcher with serializers (use only for libs) Saving soapC.c serializers
Compilation successful |
3) 第2行定义了calc.wsdl的路径
4) 第3行定义了服务地址,在客服端通过这个地址再加上端口即个访问此服务端。
5)第4行也是定义了一种地址,在calc.wsdl文件里体现如下:
<service name="calc"> <documentation>gSOAP 2.8.15 generated service definition</documentation> <port name="calc" binding="tns:calc"> <SOAP:address location="http://localhost/calc.wsdl http://localhost/calc.cgi"/> </port> <port name="calc" binding="tns:calc"> <SOAP:address location="http://localhost/calc.wsdl"/> <SOAP:address location="http://localhost"/> </port> </service> |
6) 第5 行定义了输出输出量的编码方式,使用了此行在使用soapcpp2.exe编译头时需要加“-e ”参数
<binding name="calc" type="tns:calcPortType"> <SOAP:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <operation name="add"> <SOAP:operation style="rpc" soapAction=""/> <input> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> <operation name="sub"> <SOAP:operation style="rpc" soapAction=""/> <input> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> <operation name="mul"> <SOAP:operation style="rpc" soapAction=""/> <input> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> <operation name="div"> <SOAP:operation style="rpc" soapAction=""/> <input> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> <operation name="pow"> <SOAP:operation style="rpc" soapAction=""/> <input> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </input> <output> <SOAP:body use="encoded" namespace="http://tempuri.org/ns.xsd" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/> </output> </operation> </binding> |
7) 第6行定义了wsdl中的 <portType >
<portType name="calcPortType"> <operation name="add"> <documentation>Sums two values</documentation> <input message="tns:addRequest"/> <output message="tns:addResponse"/> </operation> <operation name="sub"> <documentation>Subtracts two values</documentation> <input message="tns:subRequest"/> <output message="tns:subResponse"/> </operation> <operation name="mul"> <documentation>Multiplies two values</documentation> <input message="tns:mulRequest"/> <output message="tns:mulResponse"/> </operation> <operation name="div"> <documentation>Divides two values</documentation> <input message="tns:divRequest"/> <output message="tns:divResponse"/> </operation> <operation name="pow"> <documentation>Raises a to b</documentation> <input message="tns:powRequest"/> <output message="tns:powResponse"/> </operation> </portType> |
8) 每个函数前的注释对应calc.wsdl文件里<documentation>如上图中的每个操作的<documentation>:
<documentation>Sumstwo values</documentation>
3 将gSOAP包里的bin/win32下的soapcpp2.exe和gSOAP包里的stdsoap2.h、stdsoap2.c或stdsoap2.cpp拷贝到前面创建的工程文件夹里。
4 启动dos窗口并切换到此目录下使用soapcpp2.exe生成相应的文件。
相关参数可使用“soapcpp2.exe –help”查询,
这里我使用了soapcpp2.exe–c –e calc.h命令,只表示生成C代码,此时会生成服务端和客户端的文件及一些头文件 。
包括soapC.c 、soapClient.c、soapClientLib.c、soapServer.c、soapServerLib.c、soapH.h、soapStub.h等文件。
如果是c++,则“.c”文件换成“.cpp”。
如果只想生成服务端文件需要加参数“- S”,如果只生成客户端程序加参数“-C”。
5 将服务端需要的文件soapC.c 、soapServer.c、soapH.h、soapStub.h、stdsoap2.h、stdsoap2.c文件添加到工程里。
不需要添加soapServerLib.c文件。
此处一定要用stdsoap2.c,如果用stdsoap2.cpp会出错。
原则是要么全部是.c的文件格式,要么全部是.cpp的文件格式。
6 创建main函数文件:
#include"soapH.h" #include"calc.nsmap" #include"stdsoap2.h" #include<stdio.h> #include<stdlib.h>
int main(int argc,char **argv) { SOAP_SOCKET m, s; /* master and slave sockets */ struct soap soap; soap_init(&soap); if (argc < 2) soap_serve(&soap); /* serve as CGI application */ else { m = soap_bind(&soap, NULL, atoi(argv[1]), 100); if (!soap_valid_socket(m)) { soap_print_fault(&soap, stderr); exit(-1); } fprintf(stderr, "Socket connection successful: master socket = %d\n", m); for ( ; ; ) { s = soap_accept(&soap); fprintf(stderr, "Socket connection successful: slave socket = %d\n", s); if (!soap_valid_socket(s)) { soap_print_fault(&soap, stderr); exit(-1); } soap_serve(&soap); soap_end(&soap); } } return 0; }
int ns__add(struct soap *soap,double a, double b,double *result) { *result = a + b; return SOAP_OK; }
int ns__sub(struct soap *soap,double a, double b,double *result) { *result = a - b; return SOAP_OK; }
int ns__mul(struct soap *soap,double a, double b,double *result) { *result = a * b; return SOAP_OK; }
int ns__div(struct soap *soap,double a, double b,double *result) { if (b) *result = a / b; else { char *s = (char*)soap_malloc(soap, 1024); sprintf(s, "<error xmlns=\"http://tempuri.org/\">Can't divide %f by %f</error>", a, b); return soap_sender_fault(soap,"Division by zero", s); } return SOAP_OK; }
int ns__pow(struct soap *soap,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(soap, 1024); sprintf(s, "Can't take the power of %f to %f", a, b); sprintf(s, "<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; }
|
7 在工程“propertis”-> “configurationProterties”->“Debugging”->“command arguments”里添加端口参数4546。
8build
9 启动调试
10 在浏览器里输入“http://localhost:4546”。 如果得到如下信息则说明服务已经正常启动:
This XML file does not appear to have any style information associated with it. The document tree is shown below. <SOAP-ENV:Fault xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://tempuri.org/ns.xsd"> <faultcode>SOAP-ENV:Client</faultcode> <faultstring>HTTP GET method not implemented</faultstring> </SOAP-ENV:Fault>
|
二 客户端
1 如上炮制。
只需将上面的soapServer.c换成soapClient.c
2 编写客户端main函数文件
#include"soapH.h" #include"calc.nsmap" #include<stdio.h> #include<stdlib.h> #include"stdsoap2.h"
constchar server[] = "http://localhost:4546";//"http://websrv.cs.fsu.edu/~engelen/calcserver.cgi"; /* = "http://localhost:8080"; to test against samples/webserver */
int main(int argc,char **argv) { struct soap soap; double a, b, result; if (argc < 4) { fprintf(stderr, "Usage: [add|sub|mul|div|pow] num num\n"); exit(0); } soap_init1(&soap, SOAP_XML_INDENT); //soap_init(&soap); //printf("add(%f,%f) \n",argv[2],argv[3]); a = strtod(argv[2], NULL); b = strtod(argv[3], NULL); switch (*argv[1]) { case'a': printf("add(%f,%f) \n",a,b); soap_call_ns__add(&soap, server, NULL, a, b, &result); break; case's': soap_call_ns__sub(&soap, server,"", a, b, &result); break; case'm': soap_call_ns__mul(&soap, server,"", a, b, &result); break; case'd': soap_call_ns__div(&soap, server,"", a, b, &result); break; case'p': soap_call_ns__pow(&soap, server,"", a, b, &result); break; default: fprintf(stderr, "Unknown command\n"); exit(0); } if (soap.error) { printf("abcd\n"); soap_print_fault(&soap, stderr); exit(1); } else printf("result = %f\n", result); soap_destroy(&soap); soap_end(&soap); soap_done(&soap); return 0; }
|
此文件中已经设置了服务端的地址和端口。
3在工程“propertis”-> “configuration Proterties”->“Debugging”->“commandarguments”里添加参数“add 4.23.6”。表示进行两个数的加法
4 build
5 debug。运行,此时会得到两个参数的计算结果。
三 注意事项
1 int可以向double转,但double不能向int转,如4.2会变成0.