gsoap中文乱码及内存清理等问题的解决方案

gsoap中文乱码的问题

 -- 拔剑,2010-08-31

 

一、 问题和分析

 

gsoap在调用Webservice过程中,如果字符串中有汉字,很容易出现乱码。 由于网络间一般用UTF8表示

字串(ANSI字串- (char < 128)本身已经符合UTF8编码规则),所以ANSI字符不会乱码,而一个汉字

的传统表示需要两个字符,而在wchar_t宽字符串中只需一个字符表示。

 

一个汉字用UTF8表示通常占用3个BYTE, 如:

         你  --〉0xe4, 0xbd, 0xa0

         好  --> 0xe5, 0xbd, 0x21

 

gSoap在封装XML包时,在进行utf8字符转换时:

   1)如果入口参数为 char* / std::string (即用多字节表示汉字)时,

      汉字因为已经用2个字节(窄字符)表示,此时的UTF8编码已近不是对该汉字的码值编码,

      而是对组成该汉字的两个字符进行utf8编码,结果自然不对了。因此乱码。

                    UTF8(0xAABB)   !=  UTF8(0XAA + 0XBB)

   2)如果入口参数为 wchar_t* / std:wstring(即一个汉字用一个字符表示)时,

      汉字因为用1个宽字符表示(两个字节),因此UTF8转换没有问题。

 

gSoap在解包时,因为来源字符串已经用UTF8表示,因此在gsoap的response中,用std::string/char*,

道理上,在转换到当前字符集,应该不会乱码。

 

二、解决方案

 

   很简单,在gsoap的数据类型中,用wchar_t* 或std::wstring代替std:string/char*.同时,

为了确保Proxy类用UTF8编解码,可以在其构造函数中强行赋编码方式,如:   

          MyServiceSoapProxy gs(SOAP_C_UTFSTRING); 

 

由于gsoap的调用代码是自动生成的,如何办?

   我们需要在生成gSoap调用代码时,强制使用wchar_t*/std::wstring. 我们可以修改default类型转换

文件或者强制使用某个类型转换文件。如:

gSOAP两大工具的用法从WSDL中产生头文件,用法:
    wsdl2h -o 头文件名 WSDL文件名或URL
    wsdl2h常用选项
    -o 文件名,指定输出头文件
    -n 名空间前缀 代替默认的ns
    -c 产生纯C代码,否则是C++代码
    -s 不要使用STL代码
    -t 文件名,指定type map文件,默认为typemap.dat
    -e 禁止为enum成员加上名空间前缀
 type map文件用于指定SOAP/XML中的类型与C/C++之间的转换规则,比如在mytypema.dat(拷贝自default typemap.dat)里写
    xsd__string = | std::wstring | wchar_t*    # 注释符号为#
 那么SOAP/XML中的string将转换成std::wstring或wchar_t*,这样能更好地支持中文。

 例:

    wsdl2h -o ws.h  -n ws -t mytypemap.dat \ http://www.aaa.com/Service.asmx?WSDL
    从http://www.aaa.com/Service.asmx?WSDL 生成ws.h文件,名空间为ws,使用mytyemap.dat指定的转换规则。

 

三、一点说明

  1)入口参数,用局部变量的地址付给参数,避免内存分配销毁

  2)gSoap will use soap_malloc(..) to allocate memory, which is different from malloc()/new

     you should NOT delete memory allocated by gsoap by yourself in Response Object.

 

        GSOAP CAN AUTOMATICALLY DELETE THOSE MEMORIES IT ALLOCATED!!!!!!

 

     If you tried to delete those memory allocated by gSOAP, memory leak could appear.

     (Maybe to use soap_delete(soap*, pointer) is safe, not fully tested, and no need!)

  3)不支持__int64 (如表示时间)

     simple, directly comments out conditional macro covering

              gsoap_s2LONG64(...)

              gsoap_LONG642s(...)

     like:

             //#ifndef XXXX

             //#endif

  4) __int64转换失败问题(时间是用__int64表示的)

     In windows, use "%I64d" instead of "%lld".

  5)同时调用多个Web service接口

     自需要把Web service的WSDL文件放在一起给wsdl2h调用,如:

         wsdl2h -o ws.h -n ws -t mytypemap.dat WSDL_file1 WSDL_File2 .... WSDL_FileN

     生成的文件中,ENDPOINT被写在一个字串里面,因此需要修改生成的源代码

        const char* ENDPOINT ="http_url1  http_url2 http_url3 .. http_urlN";

     ===>

        contst char* END_POINT_IF1 = "http_url1";

        const  char* END_PINT_IF2 = "http_url2" ;

       ...

        const char* END_POIINT_IFN = "http_urlN";

    ==> 同时修改每个Webservice调用的Endpoint值,用END_POINT_IF1,....END_POINT_IFN分别替代。

 7) you can use soap_malloc(..) to create temp memory, and soap will automatically delete

    such kind of data in Proxy destructor.

 

    If you want to delete the memory by yourself, or even after soap object (Proxy) is destructed.

    You  can use

                         soap_unlink(...)

    to de-reference this allcocated memory and later use

                         free(...)

    to release the memory by yourself.

  8) Do not copy Soap PROXY instance, otherwise could cause memory issue. You can use pointer,

     or reference type to pass such parameters.

  9)二进制流的传输

     XML利用Base64编码的文本传输二进制流,WebService/gSoap支持无限制长度的二进制流传输。

     在gsoap中要传输二进制流不需要做特别的处理,gsoap会自动将数据进行Base64编解码。

 

 

四、调试

  1)察看gsoap的XML封包可以在下面的函数设置断点:

            gsoap_fsend/fsend

            gsaop_frecev/frecv

  2)数据类型转换

            gsoap_s2LONG64

            gsoap_s2int

            ...

            gsoap_LONG642s

            ...

   3) turn on

            SOAP_DEBUG

      to see more thing.

 

参考:

  http://www.cs.fsu.edu/~engelen/soapdoc2.html#tth_sEc7.2.3

  http://panxq0809.javaeye.com/blog/709173

  (其余忘记了)

上一篇:Angularjs 源码分析3


下一篇:【百度地图API】多家地图API内存消耗对比测验(带源码)