ONVIF協議網絡攝像機(IPC)客戶端程序開發(4):使用gSOAP生成Web Services框架代碼

版權聲明:本文爲博主原創文章,如要轉載請標明出處。 https://blog.csdn.net/benkaoya/article/details/72452968

1. 專欄導讀

本專欄第一篇文章「專欄開篇」列出了專欄的完整目錄,按目錄順序閱讀,有助於你的理解,專欄前面文章講過的知識點(或代碼段),後面文章不會贅述。爲了節省篇幅,突出重點,在文章中展示的示例代碼僅僅是關鍵代碼,你可以在「專欄開篇」中獲取完整代碼。

如有錯誤,歡迎你的留言糾正!讓我們共同成長!你的「點贊」「打賞」是對我最大的支持和鼓勵!

2. 不要自己造輪子

ONVIF標準是使用SOAP方式實現的Web Services,本專欄上一篇文章已經介紹了什麼是Web Services,涉及很多概念,包括SOAP、HTTP、XML,RPC等等。辣麼多東東,全部要自己碼代碼實現嗎?當然不用,我們不必自己造輪子,有現成的工具會幫我們自動生產大部分的代碼框架。

這樣的工具有很多,比如:

  1. gSOAP工具,適用於C/C++語言開發。
  2. Apache CXF工具,適用於JAVA語言開發者。

我的項目採用C/C++語言,所以本文重點講解gSOAP。後面,網絡攝像機(IPC)客戶端程序代碼都是使用gSOAP工具自動生成的,所以必須對gSOAP工具必須有一個深入的理解,爲此,我們先從簡單的例子開始理解。

3. gSOAP簡介

gSOAP官方網址:http://www.cs.fsu.edu/~engelen/soap.html

gSOAP開源版下載網址(最新版本):http://sourceforge.net/projects/gsoap2

gSOAP開源版下載網址(歷史版本):https://sourceforge.net/projects/gsoap2/files/gSOAP/

gSOAP有分商業版「commercial edition」和開源版「open source edition」,我撰寫本專欄用的gSOAP是開源版「gsoap_2.8.45」。

gSOAP 編譯工具提供了一個SOAP關於C/C++ 語言的實現,從而讓C/C++語言開發Web Services服務端或客戶端程序的工作變得輕鬆了很多。甚至,即使你對Web Services不甚瞭解都沒有關係,有了gSOAP這樣的工具,你也能開發基於SOAP方式實現的Web Services客戶端。

gSOAP到底會自動生成哪些框架代碼,下圖中淺綠色框中的部分就是自動生成的代碼。


圖1

4. gSOAP工具轉換原理


圖2

gSOAP工具根據WSDL文檔,自動生成C/C++語言的客戶端/服務端框架代碼。這其中有兩個工具很重要,wsdl2h和soapcpp2。wsdl2h工具根據WSDL文成C/C++頭文件,而soapcpp2工具則是根據該頭文件生成C/C++的框架源碼。

gSOAP工具可以在Windows、Linux和Macosx操作系統下運行,gSOAP工具包中自帶有Windows和Macosx操作系統的wsdl2h和soapcpp2可執行文件,而Linux操作系統的,得自己編譯。

通過實驗證實,用Windows和Linux工具生成的框架代碼,是一樣樣的,沒有區別。

如何使用gSOAP,在gSOAP官網,或者在工具包gsoap\doc\soapdoc2.pdf文檔中都有很詳細的說明,大家可以參考。下面我們通過「國內手機號碼歸屬地查詢」的例子,來演示如何使用gSOAP工具。

5. gSOAP演練實例:國內手機號碼歸屬地查詢

「國內手機號碼歸屬地查詢」免費WEB服務:

WEB服務地址: http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx
WSDL: http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
  1. 下載gSOAP工具,我的版本是「gsoap_2.8.45」。
  2. 創建一個文件夾MobileCode,從gSOAP工具中拷貝如下文件和文件夾到MobileCode文件夾中,

    gsoap_2.8.45\gsoap-2.8\gsoap\bin\win32\soapcpp2.exe
    gsoap_2.8.45\gsoap-2.8\gsoap\bin\win32\wsdl2h.exe
    gsoap_2.8.45\gsoap-2.8\gsoap\stdsoap2.c
    gsoap_2.8.45\gsoap-2.8\gsoap\stdsoap2.h
    gsoap_2.8.45\gsoap-2.8\gsoap\typemap.dat
    gsoap_2.8.45\gsoap-2.8\gsoap\import\
    gsoap_2.8.45\gsoap-2.8\gsoap\custom\
    

    最終效果如下:


    圖3

  3. 啓動cmd.exe,確保當前路徑在剛纔創建的MobileCode目錄下:


    圖4

  4. 使用wsdl2h工具,根據WSDL產生頭文件,在cmd中執行以下命令:

    wsdl2h.exe -o mobilecode.h -c -s -t typemap.dat http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
    

    其中-c爲產生純c代碼,默認生成 c++代碼;-s爲不使用STL庫,-t爲typemap.dat的標識。詳情可通過wsdl2h.exe -help查看幫助。

    這裏的WSDL文件,可以在wsdl2h命令中在線下載,也可以先下載到本地,然後引用本地WSDL文件,我這裏是採用在線下載方式。

  5. 使用soapcpp2工具,根據頭文件產生框架代碼,在cmd中執行以下命令:

    soapcpp2.exe -2 -C -c -x -Iimport -Icustom mobilecode.h
    

    -2爲生成SOAP 1.2版本的代碼,-C爲僅生成客戶端的代碼(服務端的不要),-c生成C語言代碼,詳情可使用soapcpp2.exe -help查看幫助。

  6. 自動生成的源碼文件如下圖所示,


    圖5

    其中custom、import、wsdl2h.exe、soapcpp2.exe、typemap.dat、mobilecode.h、soapClientLib.c這些文件已經沒用了,可以刪掉,最終剩下的文件只有:


    圖6

    在soapStub.h文件中,列出了「國內手機號碼歸屬地查詢」WEB服務的所有接口(Client-Side Call Stub Functions),我們的應用程序通過調用這些接口就成了,至於SOAP協議整個過程怎麼實現的,都在soapC.c和soapClient.c中,有興趣的可以去研究,沒興趣的就不管它了,懂得調用以下這幾個接口就可以了。


    圖7

  7. 接下來,寫個main.c,通過soap_call___ns1__getMobileCodeInfo接口來查詢國內手機號碼歸屬地信息,並將其打印出來,源碼如下所示(實例代碼已上傳網絡:點擊下載)。

        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
        #include "soapStub.h"
        #include "MobileCodeWSSoap.nsmap"
    
        void getMobileCodeInfo(char *mobileCode)
        {
            struct soap *soap = NULL;
            const char  *endpoint = "http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx";
            struct _ns1__getMobileCodeInfo          req;
            struct _ns1__getMobileCodeInfoResponse  resp;
    
            soap = soap_new();                                                          // allocate and initalize a context
    
            soap_set_mode(soap, SOAP_C_UTFSTRING);                                      // support multibyte string(for Chinese)
    
            memset(&req, 0x00, sizeof(req));
            req.mobileCode = mobileCode;
            req.userID     = NULL;
    
            if(SOAP_OK == soap_call___ns1__getMobileCodeInfo(soap, endpoint, NULL, &req, &resp)) {
                if (NULL != resp.getMobileCodeInfoResult) {
                    printf("%s\n", resp.getMobileCodeInfoResult);
                }
            }
    
            soap_destroy(soap);                                                         // delete deserialized objects
            soap_end(soap);                                                             // delete allocated data
            soap_free(soap);                                                            // free the soap struct context data
        }
    
        int main(int argc, char **argv)
        {
            if (argc < 2) {
                return 0;
            }
            getMobileCodeInfo(argv[1]);
    
            return 0;
        }

    第一次執行,如下圖所示,會出現亂碼:


    圖8

    這是由於WEB服務應答的歸屬地信息中包含有UTF-8格式的中文導致的。SOAP協議採用HTTP傳輸協議+XML數據格式,規定XML字符編碼格式必須是UTF-8。爲了解決這個問題:

    一、在源碼中加入soap_set_mode(soap, SOAP_C_UTFSTRING)語句,告知gSOAP底層代碼,我們上層傳入的字符編碼格式已經是UTF-8,,內部就不參與轉碼的過程,WEB服務器應答的UTF-8字符也都直接傳給上層,此時我們的main.c代碼收到的應答也是UTF-8格式的數據。

    二、cmd.exe環境默認的環境是「簡體中文GBK」,通過chcp命令就能查到,「活動代碼頁936」代表的就是「簡體中文GBK」,在這種環境下打印UTF-8中文字符當然會亂碼,使用命令chcp 65001將控制檯的字符集改爲UTF-8,「活動代碼頁65001」代表的就是UTF-8,如此就不會亂碼了。


    圖9

    亂碼問題,這個例子還算是簡單的,僅僅是服務器應答的時候帶有UTF-8格式的中文字符,從控制檯輸入的字符(手機號碼)是純數字的,沒有涉及到UTF-8編碼問題。如果輸入也帶有中文,那情況會更復雜,有關這方面的詳細情況,可參考我博客中此前寫的一篇文章「淺談C/C++編程中的字符編碼轉換」。

6. gSOAP演練實例:計算器

gSOAP官網有提供gSOAP演練實例「Example XML SOAP calculator client (C)」,有興趣的也可以去官網學習下。

7. 總結

對本文做個總結:

  1. 開發基於SOAP方式的Web Services,不需要自己實現代碼框架,有諸如gSOAP、Apache CXF這樣的工具會幫我們實現。


    圖10

  2. 以「國內手機號碼歸屬地查詢」爲例,重點介紹了gSOAP工具轉換原理,及其使用方法。

  3. 還遇到了SOAP協議中UTF-8中文字符打印到控制檯會亂碼的問題,並給出瞭解決方法。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章