一、准备工具
安装gsoap
二、gsoap使用
1. soapcpp2使用参数如下(soapcpp2是将.h文件解析生成.wsdl c/c++文件,工客户端服务端使用):
-1 使用SOAP 1.1进行编译
-2 使用SOAP 1.1进行编译
-C 只生成客户端代码
-S 只生成服务端代码
-T generate server autorem -test code
-L 不生成soapClientLib/soapServerLib文件(使用-i就有-L的功能,理解为将ClientLib和Client变对象)
-a use SOAPAction HTTP/WSA header to invoke serverrem -side operations
-b serialize byte arrays char[N] as string
-c 生成c源代码(没有现象) generate C source code
-dpath 生成代码路径
-e generate SOAP RPC encoding style bindings
-fN file split of N XML serializer implementations per file (N>=10)
-h display help info
-Ipath 代码导入路径
-i 从SOAP结构继承,生成C++服务代理和对象
-j 通过共享SOAP结构,生成C++服务代理和对象
-k generate data structure walkers (experimental)
-l generate linkable modules (experimental)
-m generate Matlab(tm) code for MEX compiler
-n use service name to rename service functions and namespace table
-pname 使用新前缀"name"代替"soap" save files with new prefix name instead of 'soap'
-qname 在所有声明中使用命名空间"name"(同时拥有-p功能)
-s 生成具有严格的XML验证检查反序列化代码 generate deserialization code with strict XML validation checks
-t 生成代码全部使用xsi:type类型soap/XML消息。 generate code for fully xsi:type typed SOAP/XML messaging
-u uncomment comments in WSDL/schema output by suppressing XML comments
-v 显示版本信息(没有看到现象--生成代码没有变化)
-w 不生成WSDL和模式文件
-x 不生成XML文件
-y 包括C / C++类型访问信息的示例XML消息(没有看到现象)
2.wsdl常使用的参数(wsdl是解析.wsdl文件生成c/c++代码及.h文件)
-o filename.h 将wsdl转化为filename.h头文件。
-s 不生成STL代码
-c 生成纯C风格的头文件,这将去除C++的一些特性
-n name 使用name代替默认前缀ns
-t filename.dat 使用filename.dat代替默认的typemap.dat文件
-zX 兼容之前的X版本
3.例子
编写如下.h文件
//gsoap ns1 service name: control
//gsoap ns1 service namespace: http://192.168.14.152:8888/control.wsdl
//gsoap ns1 service location: http://localhost:8888
//gsoap ns1 service executable: add.cgi
//gsoap n1s service encoding: encoded
//gsoap ns1 schema namespace: urn:control
int ns1__add(int num1,int num2,int* sum);
int ns1__div(int num1,int num2,int* result);
需注意:
(头文件第一行定义服务名称,在生成的文件中有些会以它命名;
第二行定义namespace;第三行定义客户端访问服务端地址(如果没有指定给客户端服务地址);
第四行在xml文件中体现,也是地址;第五行定义服务编码,需要soapcpp2 -e有用
第六行由于服务器接口命名空间为control,因此urn:后面必须为control
这些信息全在生成的.wsdl文件里显示
)
1、add.h文件前面的几句注释不能删除,为soapcpp2需要识别的标志;
2、接口函数的返回值只能是int,是soap调用的结果,一般通过soap.error来判断soap的连接情况,这个返回值没有用到;
3、接口函数的最后一个参数为传出参数,如果需要传出多个参数,需要自己定义一个结构将返回项封装;
4、在.h文件中不能include别的.h文件,可能不能生效,需要用到某些结构的时候需要在该文件中直接声明;
5、如果客户端的调用不需要返回值,那么最后一个参数为空;
另外,gSoap对“”和“_”(下划线、双下划线)有特殊用法,接口定义时函数名前要加上命名空间名和双下划线
举例:加法运算
int add(int num1, int num2, int &num3);
在接口头文件定义时要写成如下格式
int ns1__add(int num1, int nmu2, int &num3);
其中
“ns1”是命名空间名称,此名称可以自定义成其它名字 但其后”urn:control”不可随意更改,这个是要与服务端统一的
“__”是编译时识别符号,如果没有的话xml文件是编译不出来的
“_”(单下划线)定义名称中要慎用,自己定义的变量或函数名称中使用下划线的地方要在下划线后加上”USCORE”;
例 定义 ns1__add_sum(int num_1, int num2, int &num_3);
要写成如下形式
ns1__add_USCOREsum(int num_USCORE1, int num2, int &num_USCORE3);
“add”是接口函数名 这个是客户端与服务器统一的接口名字
这里ns1命名空间是由//gsoap ns1来的,如果写成//gsoap ns 那么函数前面命名空间为ns,如果函数前面命名空间为其他名,则生成wsdl时,使用默认的配置,不是.h头文件里配置的信息了
服务端代码(addserver.cpp):
#include "mixService.h"
#include "mix.nsmap"
#include
#include
int Service::add(int num,int num2,int* sum)
{
*sum=num+num2;
printf("sleep...\n");
sleep(5);
return 0;
}
int Service::div(int num1,int num2,int* result)
{
*result=9;
return 0;
}
int http_get(soap* soap)
{
FILE*fd = NULL;
printf("http_get\n");
char* s = strchr(soap->path,'?');
printf("soap->path: %s\n",soap->path);
/* if(!s || strcmp(s,"?wsdl"))
{
printf("?wsdl\n");
return SOAP_GET_METHOD;
}
*/
fd=fopen("./add.wsdl","rb");
if(fd==NULL)
{
return 404;
}
soap->http_content="text/xml";
soap_response(soap,SOAP_FILE);
for(;;)
{
size_t r = fread(soap->tmpbuf,1,sizeof(soap->tmpbuf),fd);
if(!r)
{
printf("finish wsdl\n");
break;
}
if(soap_send_raw(soap,soap->tmpbuf,r))
{
printf("fault transport\n");
break;
}
}
fclose(fd);
soap_end_send(soap);
return SOAP_OK;
}
int main(int argc,char**argv)
{
Service m_sev;
m_sev.fget=http_get;//发布webservice,将wsdl文件发出
if(argc<2)
{
printf("input num less\n");
return 0;
}
else
{
int n = m_sev.bind("192.168.14.194",atoi(argv[1]),1);
//printf("n: %d\n",n);
//int m = m_sev.bind(NULL,atoi(argv[1]),1);
//printf("m: %d\n",m);
if(n<0)
{
m_sev.soap_print_fault(stderr);
return 0;
}
for(;;)
{
// int r = m_sev.accept();
// fprintf(stderr,"socket connection successful:socket = %d\n",r);
printf("execute run\n");
m_sev.run(atoi(argv[1]));
printf("execute finished\n");
soap_end(&m_sev);
}
}
}
客户端代码(addclient.cpp)
#include "mixProxy.h"
#include "mix.nsmap"
int main()
{
int a=0,b=19,sum=0;
int c=2,g=5,s=0;
Proxy addp;
addp.soap_endpoint = "192.168.14.194:8888";
printf("endpoint: %s\n",addp.soap_endpoint);
addp.add("192.168.14.194:8888",NULL,a,b,&sum);
printf("sum: %d\n",sum);
addp.add(c,g,&s);
printf("s: %d\n",s);
return 0;
}
makefile文件如下:供参考
GSOAP_ROOT=/usr/local/gsoap/
GSOAP_BIN=$(GSOAP_ROOT)bin
GSOAP_I=$(GSOAP_ROOT)include
WSNAME=mix
CC=g++ -g -DWITH_NONAMESPACES
INCLUDE=-I $(GSOAP_I)
SERVER_OBJS=$(WSNAME)C.o $(WSNAME)Service.o stdsoap2.o addserver.o
CLIENT_OBJS=$(WSNAME)C.o $(WSNAME)Proxy.o stdsoap2.o addclient.o
ALL_OBJS=$(WSNAME)C.o $(WSNAME)Service.o ${WSNAME}Proxy.o addserver.o addclient.o
all:server client
${WSNAME}.wsdl:${WSNAME}.h
$(GSOAP_BIN)/soapcpp2 -p$(WSNAME) -x -i -n ${WSNAME}.h
stdsoap2.o:$(GSOAP_I)/stdsoap2.cpp
$(CC) -c $?
$(ALL_OBJS):%.o:%.cpp
$(CC) -c $? $(INCLUDE)
server:Makefile ${WSNAME}.wsdl $(SERVER_OBJS)
$(CC) -o ${WSNAME}server $(SERVER_OBJS) $(INCLUDE)
client:Makefile ${WSNAME}.wsdl $(CLIENT_OBJS)
$(CC) -o ${WSNAME}client $(CLIENT_OBJS) $(INCLUDE)
clean:
rm -f *.o *.xml *.a *.wsdl *.nsmap $(WSNAME)H.h $(WSNAME)C.cpp \
$(WSNAME)Service.cpp $(WSNAME)Proxy.cpp $(WSNAME)Stub.* $(WSNAME)$(WSNAME)Proxy.* \
$(WSNAME)$(WSNAME)Object.* $(WSNAME)ServerLib.c $(WSNAME)ClientLib.c \
$(WSNAME)server $(WSNAME)client *.xsd $(WSNAME)Service.h $(WSNAME)Proxy.h