原文网址:http://blog168.chinaunix.net/space.php?uid=789299&do=blog&id=12763
项目需要使用web service,因各方面原因选择了gSOAP,使用上之后有些后悔了,资源太少,遇到问题根本不知道该如何解决,先把遇到的问题记录下来,以后有了解决方法后再补充上。
第一个问题:使用gSOAP接收附件时,总会多出几个字符,造成附件根本打不开,一点点测试发现好像是gSOAP每次flush缓冲区时都多一个字符(猜测),实在没办法直接使用了最新的版本(gsoap-2.7.17),使用最新版本后这个问题倒是没了,随之而来就出现第二个问题。
第二个问题:发送附件时使用base64编码作为SOAP消息一部分可以正常发送,但是使用MTOM流时总是发不出去附件,这个问题真的跟踪了好长时间,发现是soap_connect->soap_connect_command->soap_try_connect_command方法时判断soap->keep_alive为真,调用了soap_closesock,把附件信息都给清除了,时间紧没办法,根本没有时间修改gSOAP代码,而且也没有这个能力,想想gSOAP是最新版应该会有些bug或新特性自己没有掌握,于是乎又降了一个版本(gsoap-2.7.16),单附件问题解决了,
第三个问题:gSOAP给CXF发送多个附件时,CXF总是报空指针异常,因前几个问题,我对gSOAP彻底失去信心了,开启了gSOAP的调试功能后发现发送的内容正常,但还是不敢确信(因为我发现gSOAP日志是在实际发送之前进行的记录),找了个SmartSniffer抓包工具进行分析,用SmartSniffer抓包的时候包信息还真不全,反复几次发现是SmartSniffer缓冲区有限,存不了那么多内容,遂改用WireShark,抓的信息是全的,因对SOAP协议不是很了解,大致看了一下SOAP包内容,引用ID和边界看着都是正确的,应该不是gSOAP的问题,因个人能力有限此问题没法再进一步确定原因,只能遗留,初定将底层的多附件发送改成多个单附件发送,尽量做到上层用户体验不到这种变化。此题有解了,原来是service有问题,无法解析多附件。
上三个问题基本解决后,又有了新的需求,因数据量大,网络传输很耗时,需要用gZIP压缩后传输,看了一下gSOAP文档,需要用到zlib,到sourceforge上下了zlib的库后,编译成libz.a(Windows平台下使用cygwin)静态库添加到了工程中,并对工程进行了一些基本的设置后调试信息显示成功了。
以下内容摘自gSOAP用户向导。
19.25 Zlib 压缩
如果您想要使用Zlib进行gzip压缩,但系统上没有zlib,可以到http://www.zlib.org上下载zlib安装。
使用-DWITH_GZIP选项编译所有包含了stdsoap2.h或soapH.h的源程序,并将zlib库链接到您的代码,比如:在Unix/Linux平台下使用-lz。
gzip压缩会作用于(is orthogonal to)所有传输编码(transport encodings),比如:HTTP,SSL,DIME,也可以应用于其它传输层。您甚至可以保存和加载压缩的XML文件。
gSOAP supports two compression formats: deflate and gzip.
The gzip format is used by default.
gSOAP支持deflate和gzip两种压缩格式。默认使用gzip格式。相比于deflate,gzip有几个好处:首先,gSOAP能自动检测gzip压缩的inbound消息,甚至是没有HTTP头,通过检查消息内容的gzip头。
其次,gzip包含CRC32检验和,能确保消息被正确接收。
第三,gzip压缩的内容可以用其他软件解压,所以您可以解压gSOAP保存的gzip格式的XML文件。
在编译源码时使用-DWITH_GZIP启用gzip压缩。传送gzip压缩的SOAP/XML数据,应设置输出模式为SOAP_ENC_ZLIB,例如:
soap init(&soap);
...
soap_set_omode(&soap,
SOAP_ENC_ZLIB); // enable Zlib’s gzip
if (soap_call_ns_myMethod(&soap, . . . ))
...
soap_clr_omode(&soap,
SOAP_ENC_ZLIB); // disable Zlib’s gzip
...
在安装zlib并在链接时使用-DWITH_GZIP前提下,上例会发送一个压缩的SOAP/XML请求给服务。
自动接收HTTP传输的gzip或deflate格式压缩的SOAP/XML消息。接收压缩消息的服务端不必设置SOAP_ENC_ZLIB标志。gSOAP自动接收或读没有HTTP头的gzip压缩的SOAP/XML。
可以通过设置soap.z_level这1~9来控制outbound消息的压缩级别,1为最高效率,9为最大压缩,比如:
soap_init(&soap);
...
soap_set_omode(&soap, SOAP_ENC_ZLIB);
soap.z level = 9; // best compression
...
为确认和查看压缩率,可以使用soap.z_ratio_in和soap.z_ratio_out。这两个浮点数的值位于0.0到1.01之间,表示压缩后的消息长度和未压缩的消息长度的比值。
soap_call_ns_myMethod(&soap, . . . );
...
printf(”Compression ratio: %f%% (in) %f%% (out)\n”, 100*soap.z ratio out, 100*soap.z ratio in);
...
注:比率越低代表压缩比越高
压缩传输需要缓冲整个输出消息,以确定HTTP消息长度。这意味着在给发送压缩消息设置SOAP_ENC_ZLIB标志时,SOAP_IO_STORE标志会被自动设置。使用HTTP块会显著减少内存的使用,并可能提高压缩的SOAP/XML消息的传输速度,这在为输出模式设置SOAP_ENC_ZLIB和SOAP_IO_CHUNK标志后完成。然而,一些web服务器不接收HTTP块请求消息(尽管他们返回HTTP块消息!)。stand-alone gSOAP服务总是接收块请求消息。
编译源码时设置了-DWITH_ZLIB时,会限制用deflate格式压缩和解压缩。只有纯(plain)和deflated的消息能够被传输,设置此模式时不支持gzip。即使没有HTTP头,接收gzip压缩的内容也是自动的。但对于没有HTTP头的deflate压缩的内容接收不是自动的,需要为输入模式设置SOAP_ENC_ZLIB。
注意:在编译包含stdsoap2.h或soapH.h头文件的源文件(比如:stdsoap2.h,soapC.cpp,soapClient.cpp等)时,WITH_GZIP和WITH_ZLIB选项必须定义一致;如果使用的宏不一致,应用程序可能会崩(crash),因为访问和定义gSOAP环境变量不匹配。