1. 程式人生 > >gsoap中文亂碼及記憶體清理等問題的解決方案

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.

參考:

  (其餘忘記了)