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


1. 專欄導讀

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

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

2. 前言

前一篇文章介紹了什么是ONVIF,也梳理了ONVIF開發流程,本文接着介紹些如何使用gSOAP工具生成ONVIF協議框架代碼。

本文生成的ONVIF協議框架代碼,后續文章都會用到,我這里會考慮生成「大而全」的代碼以支撐后續的文章。主要體現在:

  • 一次性把所有可能會用到的WSDL文檔都納入編譯,以便得到一份盡可能齊全的ONVIF接口代碼。我這樣做是為了省事,但我希望你在心底里能明白一件事情:ONVIF有好多個模塊,每個模塊分別對應着不同的WSDL文檔,如果你只是想實現其中某個模塊的功能,其實只要拿那個模塊對應的WSDL文檔來編譯即可(可以忽略其他WSDL)。比如你只是想實現「設備發現」功能,只要拿remotediscovery.wsdl來編譯即可。

  • 為了讓代碼同時兼容Windows和Linux兩個平台(未考慮其他平台),在我后續專欄中的示例代碼都會做一些兼容性的處理。如果你是用Windows來開發,那得用Microsoft Visual Studio SP1(或更高版本),后續會涉及到SOAP協議數據「中文字符亂碼」的問題,Microsoft Visual Studio SP1以下的版本不好處理。

  • 把我所遇到的問題盡可能的提前進行說明,至於沒其他問題,只能大家自己搞定了,也歡迎大家來一起交流(留言/郵箱)。

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」。

4. wsdl2h和soapcpp2簡介

要用gsoap生成onvif源碼,必須用到wsdl2h和soapcpp2兩個工具(執行文件)。在gsoap\bin目錄下,win32和macosx平台已經有現成的了(官方幫我們編譯好了的),linux下的要自己編譯咯,可參考INSTALL.txt文件進行編譯安裝(不同gSOAP版本的編譯安裝方法會略有不同,以你gSOAP版本中的INSTALL.txt為准)。

通過實驗證實,wsdl2h和soapcpp2兩個工具,不管是Windows版的,還是Linux版的,它們從WSDL轉成的框架代碼,是一樣樣的,沒有區別。

5. wsdl2h不支持HTTPS

既然有現成的Windows版wsdl2h.exe,那就直接拿來用咯。結果讓人沮喪,在從ONVIF的WSDL轉為頭文件時出錯,錯誤信息如下:

wsdl2h.exe -P -x -o onvif.h -c -s -t typemap.dat  https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/ver10/media/wsdl/media.wsdl
Saving onvif.h

** The gSOAP WSDL/WADL/XSD processor for C and C++, wsdl2h release 2.8.45
** Copyright (C) 2000-2017 Robert van Engelen, Genivia Inc.
** All Rights Reserved. This product is provided "as is", without any warranty.
** The wsdl2h tool and its generated software are released under the GPL.
** ----------------------------------------------------------------------------
** A commercial use license is available from Genivia Inc., contact@genivia.com
** ----------------------------------------------------------------------------

Reading type definitions from type map "typemap.dat"

Cannot connect to https site: SSL/TLS support not enabled, please rebuild wsdl2h with SSL/TLS enabled using 'make secure' or download the WSDL/WADL and XSD files and rerun wsdl2h on these files directly by specifying the file names on the command line.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

從提示信息也能看出大概意思,就是wsdl2h不支持SSL/TLS,無法下載HTTPS文件。我2016年9月份也有用gSOAP生成ONVIF代碼,為啥沒碰到這個問題,而現在(2017年4月25日)卻碰到了?

早期,ONVIF的WSDL文檔URL地址是HTTP開頭的(不會出現這個問題),2017年3月底ONVIF官網進行了一次改版,改版之后WSDL的URL地址變成HTTPS的了,即使你訪問早期的HTTP地址,如:

http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl

最終也會被跳轉到HTTPS地址:

https://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl

gSOAP官方提供的、已編譯好的wsdl2h默認是禁用SSL/TLS的,所以不支持HTTPS下載WSDL文件。至少我的版本gsoap_2.8.45是如此,未來的版本會如何只能靠大家自己嘗試。根據出錯的提示信息,有兩種解決辦法:

  1. 重新編譯gSOAP源碼,生成帶SSL/TLS的wsdl2h工具。
  2. 自己手動下載WSDL文檔后,再用本地WSDL文檔執行wsdl2h命令。

網上很多教程有提到使用第2種方法,這對其他的WSDL文檔可能合適,但對ONVIF的WSDL不合適,ONVIF的WSDL文檔會依賴其他WSDL和xsd文檔,依賴關系隱藏在每個WSDL文檔中,一般人很難厘清這里面復雜的依賴關系,容易出錯,也整不清楚xsd文件該從哪里下載。

所以這里推薦用第1種方法,如何編譯gSOAP源碼,以便得到開啟SSL/TLS的wsdl2h,不同版本的gSOAP方法不同,具體要參考對應gSOAP版本中的INSTALL.txt文件說明。

6. 編譯gSOAP源碼讓wsdl2h支持HTTPS

下面介紹下如何在linux平台下重新編譯gSOAP源碼,以便得到開啟SSL/TLS的wsdl2h,從而讓wsdl2h支持HTTPS。

6.1 准備環境

在編譯安裝之前,必須先安裝以下幾個要用到的軟件(在INSTALL.txt文件中有說明):

  1. 安裝Bison

    我采用源碼編譯安裝的方式:

    官網:http://www.gnu.org/software/bison/
    版本:bison-2.7.91.tar.gz
    安裝:詳見bison-2.7.91/INSTALL說明

  2. 安裝Flex

    我采用源碼編譯安裝的方式:

    官網:http://flex.sourceforge.net/
    版本:flex-2.6.0.tar.gz
    安裝:詳見flex-2.6.0/INSTALL說明

  3. 安裝OpenSSL

    我采用源碼編譯安裝的方式:

    官網:https://www.openssl.org/
    版本:openssl-1.0.2h
    安裝:詳見openssl-1.0.2h/INSTALL說明
    備注:我采用默認安裝路徑/usr/local/ssl/,這個路徑等下編譯gSOAP源碼時會用到

6.2 編譯gSOAP源碼

如何編譯,參考gsoap-2.8/INSTALL.txt說明:

$ cat INSTALL.txt

INSTALLATION

See README.txt for an overview of the gSOAP software.

Visit www.genivia.com/downloads.html for download and installation instructions.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

按提示,訪問www.genivia.com/downloads.html查看詳細的安裝說明,詳見「Installing gSOAP on Unix/Linux」章節,除此之外,你也可以通過./configure -h查看更多的幫助信息。

編譯gSOAP源碼的命令如下:

$ cd gsoap-2.8
$ ./configure --with-openssl=/usr/local/ssl
$ make
$ make install
    
    
   
   
           
   
   
  
  
          
  • 1
  • 2
  • 3
  • 4

期間如果提示找不到OpenSSL庫文件,那檢查下–with-openssl有沒有指向正確的路徑。

查看wsdl2h和soapcpp2被安裝到哪里了:

$ which wsdl2h soapcpp2
/usr/local/bin/wsdl2h
/usr/local/bin/soapcpp2
    
    
   
   
           
   
   
  
  
          
  • 1
  • 2
  • 3

看是否能運行:

$ wsdl2h -h
wsdl2h: error while loading shared libraries: libssl.so.1.0.0: cannot open shared object file: No such file or directory
    
    
   
   
           
   
   
  
  
          
  • 1
  • 2

提示找不到OpenSSL動態庫文件,解決方法:

  1. 將.so文件路徑「/usr/local/ssl/lib」追加到/etc/ld.so.conf文件末尾。

    $ echo /usr/local/ssl/lib >> /etc/ld.so.conf
          
          
         
         
                 
         
         
        
        
                
    • 1
  2. 使得修改立刻生效:

    $ ldconfig
          
          
         
         
                 
         
         
        
        
                
    • 1

至此wsdl2h就能正常運行了。

7. 使用gSOAP生成ONVIF框架代碼

gSOAP官網上有一篇文章「How do I use gSOAP with the ONVIF specifications」,專門介紹如何使用gSOAP生成ONVIF框架代碼,鏈接如下:

地址:https://www.genivia.com/resources.html

找到「How do I use gSOAP with the ONVIF specifications」章節。

操作步驟如下:

(1). 參考gSOAP官網說明修改gsoap\typemap.dat

參考「How do I use gSOAP with the ONVIF specifications」(https://www.genivia.com/resources.html)說明,看是否需要修改typemap.dat。我用的gSOAP工具版本是gsoap_2.8.45,typemap.dat文件剛好符合要求,不用改。

(2). 使用wsdl2h工具,根據WSDL產生頭文件

創建一個目錄samples/onvif,用於存放生成的ONVIF框架源碼。

$ cd gsoap-2.8/gsoap/
$ mkdir -p samples/onvif
$ wsdl2h -P -x -c -s -t ./typemap.dat -o samples/onvif/onvif.h https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/ver10/media/wsdl/media.wsdl
    
    
   
   
           
   
   
  
  
          
  • 1
  • 2
  • 3

各個選項的含義,可通過wsdl2h.exe -help查看幫助。其中-c為產生純c代碼,不然為c++代碼;-s為不使用STL庫,-t為typemap.dat的標識。

命令成功執行后會得到onvif.h頭文件,命令執行過程如下:

$ wsdl2h -P -x -c -s -t ./typemap.dat -o samples/onvif/onvif.h https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl https://www.onvif.org/ver10/media/wsdl/media.wsdl
Saving samples/onvif/onvif.h

The gSOAP WSDL/WADL/XSD processor for C and C++, wsdl2h release 2.8.45
Copyright (C) 2000-2017 Robert van Engelen, Genivia Inc.
All Rights Reserved. This product is provided "as is", without any warranty.
The wsdl2h tool and its generated software are released under the GPL.
----------------------------------------------------------------------------
A commercial use license is available from Genivia Inc., contact@genivia.com
** ----------------------------------------------------------------------------

Reading type definitions from type map "./typemap.dat"
Connecting to 'https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl' to retrieve WSDL/WADL or XSD... connected, receiving...
Done reading 'https://www.onvif.org/ver10/network/wsdl/remotediscovery.wsdl'
Connecting to 'https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl' to retrieve WSDL/WADL or XSD... connected, receiving...
Connecting to 'https://www.onvif.org/ver10/device/wsdl/../../../ver10/schema/onvif.xsd' to retrieve schema '../../../ver10/schema/onvif.xsd'... connected, receiving...
Connecting to 'http://docs.oasis-open.org/wsn/b-2.xsd' to retrieve schema... connected, receiving...
Connecting to 'http://docs.oasis-open.org/wsrf/bf-2.xsd' to retrieve schema... connected, receiving...
Done reading 'http://docs.oasis-open.org/wsrf/bf-2.xsd'
Connecting to 'http://docs.oasis-open.org/wsn/t-1.xsd' to retrieve schema... connected, receiving...
Done reading 'http://docs.oasis-open.org/wsn/t-1.xsd'
Done reading 'http://docs.oasis-open.org/wsn/b-2.xsd'
Connecting to 'https://www.onvif.org/ver10/device/wsdl/../../../ver10/schema/common.xsd' to retrieve schema... connected, receiving...
Done reading 'https://www.onvif.org/ver10/device/wsdl/../../../ver10/schema/common.xsd'
Done reading '../../../ver10/schema/onvif.xsd'
Done reading 'https://www.onvif.org/ver10/device/wsdl/devicemgmt.wsdl'
Connecting to 'https://www.onvif.org/ver10/media/wsdl/media.wsdl' to retrieve WSDL/WADL or XSD... connected, receiving...
Done reading 'https://www.onvif.org/ver10/media/wsdl/media.wsdl'

Warning: 2 service bindings found, but collected as one service (use option -Nname to produce a separate service for each binding)

To finalize code generation, execute:
> soapcpp2 samples/onvif/onvif.h

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

(3). 因「鑒權(認證)」需要,修改onvif.h頭文件

有些ONVIF接口調用時需要攜帶認證信息,要使用soap_wsse_add_UsernameTokenDigest函數進行授權,所以要在onvif.h頭文件開頭加入

#import "wsse.h"
    
    
   
   
           
   
   
  
  
          
  • 1

如果onvif.h不加入#import "wsse.h",使用soap_wsse_add_UsernameTokenDigest函數會導致編譯出錯(錯誤信息如下):

wsse2api.c(183): error C2039: “wsse__Security”: 不是“SOAP_ENV__Header”的成員
    
    
   
   
           
   
   
  
  
          
  • 1

(4). 使用soapcpp2工具,根據頭文件產生框架代碼

$ soapcpp2 -2 -C -L -c -x -I import:custom -d samples/onvif/ samples/onvif/onvif.h
    
    
   
   
           
   
   
  
  
          
  • 1

各個選項的含義,通過soapcpp2.exe -help查看幫助。

根據不同的gSOAP版本,這個過程你可能會遇到這樣的錯誤:

wsa5.h(288): **ERROR**: service operation name clash: struct/class 'SOAP_ENV__Fault' already declared at wsa.h:273
    
    
   
   
           
   
   
  
  
          
  • 1

之所有會出現這個錯誤,是因為onvif.h頭文件中同時:

#import "wsdd10.h" // wsdd10.h中又#import "wsa.h"
#import "wsa5.h"   // wsa.h和wsa5.h兩個文件重復定義了int SOAP_ENV__Fault
    
    
   
   
           
   
   
  
  
          
  • 1
  • 2

解決方法:修改import\wsa5.h文件,將int SOAP_ENV__Fault修改為int SOAP_ENV__Fault_alex,再次使用soapcpp2工具編譯就成功了,命令執行過程如下:

$ soapcpp2 -2 -C -L -c -x -I import:custom -d samples/onvif/ samples/onvif/onvif.h  

** The gSOAP code generator for C and C++, soapcpp2 release 2.8.45
** Copyright (C) 2000-2017, Robert van Engelen, Genivia Inc.
** All Rights Reserved. This product is provided "as is", without any warranty.
** The soapcpp2 tool and its generated software are released under the GPL.
** ----------------------------------------------------------------------------
** A commercial use license is available from Genivia Inc., contact@genivia.com
** ----------------------------------------------------------------------------

soap12.h(54): WARNING: option -1 or -2 overrides SOAP-ENV namespace

soap12.h(55): WARNING: option -1 or -2 overrides SOAP-ENC namespace

Using project directory path: samples/onvif/
Saving samples/onvif/soapStub.h annotated copy of the source interface file
Saving samples/onvif/soapH.h serialization functions to #include in projects
Using wsdd service name: wsdd
Using wsdd service style: document
Using wsdd service encoding: literal
Using wsdd schema import namespace: http://schemas.xmlsoap.org/ws/2005/04/discovery
Saving samples/onvif/wsdd.nsmap namespace mapping table
Using tdn service name: RemoteDiscoveryBinding
Using tdn service style: document
Using tdn service encoding: literal
Using tdn schema namespace: http://www.onvif.org/ver10/network/wsdl
Saving samples/onvif/RemoteDiscoveryBinding.nsmap namespace mapping table
Using tds service name: DeviceBinding
Using tds service style: document
Using tds service encoding: literal
Using tds schema namespace: http://www.onvif.org/ver10/device/wsdl
Saving samples/onvif/DeviceBinding.nsmap namespace mapping table
Using trt service name: MediaBinding
Using trt service style: document
Using trt service encoding: literal
Using trt schema namespace: http://www.onvif.org/ver10/media/wsdl
Saving samples/onvif/MediaBinding.nsmap namespace mapping table
Saving samples/onvif/soapClient.c client call stub functions
Saving samples/onvif/soapC.c serialization functions

Compilation successful (2 warnings)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

(5). 拷貝其他還有會用的源碼

$ cp stdsoap2.c stdsoap2.h plugin/wsaapi.c plugin/wsaapi.h custom/duration.c custom/duration.h  samples/onvif/
    
    
   
   
           
   
   
  
  
          
  • 1

soapC.c會調用到soap_in_xsd__duration函數,需要duration.c和duration.h文件。

后續示例代碼會調用到soap_wsa_rand_uuid函數(用於生成UUID),需要wsaapi.c和wsaapi.h文件。

(6). 關聯自己的命名空間,修改stdsoap2.c文件

在samples\onvif\stdsoap2.h中有命名空間「namespaces變量」的定義聲明,如下所示:

extern SOAP_NMAC struct Namespace namespaces[];
    
    
   
   
           
   
   
  
  
          
  • 1

但「namespaces變量」的定義實現,是在samples\onvif\wsdd.nsmap文件中,為了后續應用程序要順利編譯,修改samples\onvif\stdsoap2.c文件,在開頭加入:

#include "wsdd.nsmap"
    
    
   
   
           
   
   
  
  
          
  • 1

當然,你可以在其他源碼中(更上層的應用程序源碼)include,我這里是選擇在stdsoap2.c中include

(7). 大功告成

至此,我開發IPC客戶端程序要用到的ONVIF框架代碼已經生成。我專欄里的上層實例代碼就是基於這份ONVIF框架代碼而開發的。

$ ls -l onvif/
總用量 9796
-rwxrwxrwx 1 root root 2254 427 17:02 DeviceBinding.nsmap -rwxrwxrwx 1 root root 6725 429 14:30 duration.c -rwxrwxrwx 1 root root 4051 429 14:30 duration.h -rwxrwxrwx 1 root root 2254 427 17:02 MediaBinding.nsmap -rwxrwxrwx 1 root root 3031182 427 16:57 onvif.h -rwxrwxrwx 1 root root 2254 427 17:02 RemoteDiscoveryBinding.nsmap -rwxrwxrwx 1 root root 9277873 427 17:02 soapC.c -rwxrwxrwx 1 root root 406017 427 17:02 soapClient.c -rwxrwxrwx 1 root root 5158122 427 17:02 soapH.h -rwxrwxrwx 1 root root 1344868 427 17:02 soapStub.h -rwxrwxrwx 1 root root 593718 429 14:30 stdsoap2.c -rwxrwxrwx 1 root root 151026 429 14:30 stdsoap2.h -rwxrwxrwx 1 root root 64006 429 14:29 wsaapi.c -rwxrwxrwx 1 root root 7153 429 14:29 wsaapi.h -rwxrwxrwx 1 root root 2254 427 17:02 wsdd.nsmap
    
    
   
   
           
   
   
  
  
          
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

其中onvif.h文件其實已經沒用了,可以刪掉,不需要參與后續IPC客戶端程序的編譯。這里有好多個命名空間的.nsmap文件,文件內容都一模一樣,拿wsdd.nsmap一個來用即可,其他也沒卵用。

8. 我的封裝

開發調用ONVIF接口的應用程序,會比較枯燥,很多復雜、粘貼,而且會很多重復代碼,為了減少冗余,也為了后續專欄更好展示關鍵代碼,我對常用的、會頻繁調用的ONVIF接口做了二次封裝,詳細的代碼,請參考「《ONVIF協議網絡攝像機(IPC)客戶端程序開發》專欄的示例代碼」中的comm文件夾,代碼下載地址詳見前面的「專欄導讀」。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM