天天看點

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*,這樣能更好地支援中文。

 例:

三、一點說明

  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.

參考:

  (其餘忘記了)