ONVIF协议网络摄像机(IPC)客户端程序开发(4):使用gSOAP生成Web Serv

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;
        }
       
       
    • 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

    第一次执行,如下图所示,会出现乱码:


    图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中文字符打印到控制台会乱码的问题,并给出了解决方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值