新年伊始,想把onvif和gsoap boa这三个东西学习下,并作下笔记,当然为了省时间,我昨天下午看了一个下午的gsaop官网pdf感触良多,也做了小测试,废话少说,一下也有一些是摘自网友博客,大部分和pdf上说的翻译版,所以有好多雷同;
http://www.cnblogs.com/linxr/archive/2011/10/17/2215285.html
http://www.cs.fsu.edu/~engelen/soap.html
http://g.51cto.com/flower454/66952
http://www.cppblog.com/pansunyou/archive/2013/08/05/137563.html
http://www.cppblog.com/pansunyou/archive/2013/08/05/137563.html
http://software.intel.com/zh-cn/blogs/2013/05/09/gsoap实现高性能服务inter
http://www.cppblog.com/woaidongmao/archive/2008/05/28/51400.html gsoap中文文档
>>用C实现WebService,gsoap是最好的选择了。近一个月都在折腾这个,做个总结吧,估计会写得比较长。因为其中碰到了不少问题,但最终都解决调了。
>>快速开始
1. gsoap官网。遇到问题时,官网往往是最能提供帮助的地方。
http://gsoap2.sourceforge.net/
2. 几个值得参考的链接。
GSoap使用心得: http://www.cppblog.com/qiujian5628/archive/2008/10/11/54019.html
GSoap接口定义: http://blog.sina.com.cn/s/blog_5ee9235c0100de3g.html
>>测试代码。
我是在linux下用C开发的,那就Makefile入手吧。至于服务端的代码,和客户端的代码,可以参考《GSoap使用心得》,或者是gsoap自带的例子。
a. 用soapcpp2生产gsoap相关代码: $(GSOAP_BIN)/soapcpp2 -c -x
${WSNAME}.h
b. 服务端所需的代码: soapC.c soapServer.c
stdsoap2.c
c. 客户端所需的代码: soapC.c soapClient.c
stdsoap2.c
d.
其中stdsoap2.c是从gsoap开发包中复制过来的,他的文件是(a)中命令产生的。
-------------分隔符------------------------------------
GSOAP_BIN=/usr/local/gSOAP/bin
WSNAME0=soap
WSNAME=SmsWBS
SERVER_OBJS=$(WSNAME0)C.o
$(WSNAME0)Server.o stdsoap2.o
${WSNAME}server.o
CLIENT_OBJS=$(WSNAME0)C.o $(WSNAME0)Client.o
stdsoap2.o ${WSNAME}client.o
AA_OBJS=$(WSNAME0)C.o
$(WSNAME0)Server.o $(WSNAME0)Client.o stdsoap2.o ${WSNAME}server.o
${WSNAME}client.o
INCLUDE=
LIBS=
CC=g++ -g -DWITH_NONAMESPACES
#LIBS=-lz -lc -lncurses -lssl -lcrypto
#CC=g++ -g -DWITH_NONAMESPACES
-DWITH_OPENSSL
all:server
all:client
${WSNAME}.wsdl:${WSNAME}.h
$(GSOAP_BIN)/soapcpp2 -c
-x ${WSNAME}.h
$(AA_OBJS):%.o:%.c
$(CC) -c $? $(INCLUDE)
server:Makefile ${WSNAME}.wsdl $(SERVER_OBJS)
$(CC) $(SERVER_OBJS) $(LIBS) -o Smsserver -lpthread
client:Makefile ${WSNAME}.wsdl $(CLIENT_OBJS)
$(CC) $(CLIENT_OBJS) $(LIBS) -o Smsclient
clean:
rm -f *.o *.xml *.a *.wsdl *.nsmap
\
$(WSNAME0)H.h $(WSNAME0)C.c $(WSNAME0)Server.c
$(WSNAME0)Client.c \
$(WSNAME0)Stub.*
$(WSNAME)$(WSNAME)Proxy.* $(WSNAME)$(WSNAME)Object.* \
$(WSNAME0)ServerLib.c $(WSNAME0)ClientLib.c $(WSNAME)server ns.xsd
$(WSNAME)test
clear:
rm -f *.o
ns.xsd
-------------分隔符------------------------------------
>>接口定义,可参考《GSoap接口定义》。这里我将给出C#引用这个webserver所对应的接口形式。
gsoap是根据我们定义好的.h文件,然后用工具产生了我们所需的.c文件。所以我们必须根据gsoap的要求编写.h。
1.
单个参数的传出:
int ns__add( int a, int b, int *c
);
需要说明的是,这里的ns__是必须的,必须以开始注释中的ns加两个下划线开始。返回值必须是int。
但是这里的int并不是接口的返回值,而是gsoap内部的返回值。真正的返回值是int
*c。
C#中对应的接口: int add( int a, int b ); 返回值就是上述的int
*c参数。
2.
多个参数传出,在接口中必须使用结构体
typedef char *
xsd__string;
typedef long
xsd__int;
struct
ns__personResponse{
xsd__int
age;
xsd__string
name;
xsd__string
address;
};
int
ns__person( xsd__string buf_in, struct ns__personResponse * buf_out
);
在C#中,并不是我们所声明的这样。而是:int person( string buf_in, out string name, out string
address );
即,结构体中的第一个域会变成返回值,其他的变成一个个的输出参数。
3.
返回结构体。如果要返回结构图,那么必须在结构体中再套一层结构体:
typedef char *
xsd__string;
typedef long
xsd__int;
struct
ns__person{
xsd__int
age;
xsd__string
name;
xsd__string
address;
};
struct
ns__personResponse{
xsd__int
ret;
struct ns__person
person;
};
int
ns__person( xsd__string buf_in, struct ns__personResponse * buf_out
);
那么在C#中,看到的接口是这样的:int person( string buf_in, person对应的结构类
);
4.
接口中的下划线,如果接口中的交易名有下划线,必须这么声明:
int
ns__echo_USCOREreverse( char * buf_in, char ** buf_out
);
那么,C#中实际上的接口名就是:string echo_reverse( string buf_in );
>>gsoap中返回字符串
1.
下面是一个逆转字符串的函数。
int ns__echo_USCOREreverse( char *
buf_in, char ** buf_out );
int
ns__echo_USCOREreverse( struct soap *add_soap, char *buf_in, char **buf_out
)
{
int i, j, len;
printf(
"ns__interface: in=[%s]\n", buf_in
);
len
= strlen(buf_in);
*buf_out =
(char*)soap_malloc( add_soap, len+1
);
for( i=len-1, j=0; i>=0;
i--, j++
){
(*buf_out)[j] = buf_in[i];
}
(*buf_out)[j] = 0;
return
0;
}
其中调用soap_malloc申请空间,并且将他赋给返回参数buf_out。这个空间会在调用soap_end时被释放。
>>gsoap传输中文。我使用utf-8编码格式来支持汉字的传输。
1. 设置gsoap为utf-8传输数据
soap_set_mode(
&SmsWBS_soap, SOAP_C_UTFSTRING );
//设置编码
SmsWBS_soap.mode|=SOAP_C_UTFSTRING;
2. 使用下面得函数转换我们的传输内容,即将我们的数据转成UTF-8编码:
int
conv_charset( const char *dest, const char *src, char *input, size_t ilen, char
*output, size_t olen )
{
int convlen =
olen;
iconv_t conv =
iconv_open( dest, src );
if(
conv == (iconv_t) -1
)
return
-1;
memset( output, 0, olen );
if( iconv( conv, &input, &ilen, &output, &olen )
){
iconv_close(conv);
return -1;
}
iconv_close(conv);
return
convlen-olen;
}
例子:
conv_charset( "UTF-8", "GBK", "林学任.linxr", strlen("林学任.linxr"),
buf_out->name, 100
);
>>webserver发布
1.
在C#中,可以直接引用一个webserver,但是我们写得webserver如何能用被其引用呢。其实只要实现gsoap的fget回调函数即可:
SmsWBS_soap.fget = http_get;
2.
http_get函数实现
int http_get(struct soap *
soap)
{
FILE *fd =
NULL;
char *s = strchr( soap->path, ‘?‘
);
if( !s || strcmp( s,
"?wsdl" )
){
return SOAP_GET_METHOD;
}
fd = fopen( "SmsWBS.wsdl", "rb"
);
if
(!fd){
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
){
break;
}
if( soap_send_raw( soap, soap->tmpbuf, r)
){
break;
}
}
fclose(fd);
soap_end_send(soap);
return SOAP_OK;
}
原文:http://www.cnblogs.com/pengkunfan/p/3551608.html