onvif_gsoap开发中的一些疑虑

本文深入探讨了ONVIF-GSOAP开发中的一些关键概念和技术细节,包括soap结构、keep_alive状态、gsoap生成的XML协议信息以及HTTP协议部分的生成与处理流程。详细解释了如何在gsoap中实现SOAP消息的发送与接收,包括参数设置、错误处理和数据解析等核心环节。

onvif_gsoap开发中的一些疑虑

原文链接:http://hi.baidu.com/gpf626487/item/77e50c57fc5e2b3e32e0a9ce

    ①(*********)soap结构中count(soap->count)成员记录的是http协议中Content-Length的数值;

    ②keep_alive既是在通讯过程中的正常链接的一个状态标示也是关系到http协议中Connection:keep-alive的填写open还是close.

    1)    gsoap中生成的*.c文件中在生成xml协议信息时,是通过soap->fposthdr,soap_puthttphdr生成一些http协议部分.

    2)在gsoap通讯过程中,通过soap->fpost(),生成发送协议中的http协议部分.

函数soap_set_local_namespaces(struct soap *soap)

    3)soap_connect()函数中把原来的soap->mode进行了修改,这样在下次调用,同时对填入soap->buf的字符进行计数,在函数soap_connect()中soap->bufidx统计的是http协议部分的字符数;在soap_envelope_begin_out()统计envelope部分的计数,同时填写xml中envelope部分;soap_putheader()统计putheader部分的计数,同时填写xml中putheader部分;soap_body_begin_out()统计body部分的计数,同时填写xml中body部分;soap_put___tds__(*)(*标示相关功能标识,例如GetNetworkInterfaces)统计__(*)(*标示相关功能标识,例如GetNetworkInterfaces)部分的计数,同时填写xml中__(*)(*标示相关功能标识,例如GetNetworkInterfaces)部分;soap_body_end_outconnect()中soap->bufidx统计的是body部分结束标签的字符数同时把结束标签写入xml;soap_envelope_end_out()同前;soap_end_send()->soap_flush()->soap_flush_raw()->soap->fsend(),在函数soap_end_send()中进行sock发送,在此函数中第一次使用soap结构(接受/发送结束),对soap->budidx,soap->count进行清零.在 次之前结构中soap->buflen一次未用到,猜测次成员只在解析时使用.在这些处理过程中,如果(soap->bufidx > SOAP_BUFLEN),那么,由于soap_connect()已经建立了socket通讯,所以只要条件满足就用soap->flush()把buf中的协议包发送给服务器端,不会丢失协议内容,至于服务器端怎样处理,只有读代码了.

    4)soap_element()

  { if (soap->namespaces && !soap->local_namespaces)
  { register const struct Namespace *ns1;
    register struct Namespace *ns2;
    register size_t n = 1;
   for (ns1 = soap->namespaces; ns1->id; ns1++)
      n++;
    n *= sizeof(struct Namespace);
    ns2 = (struct Namespace*)SOAP_MALLOC(soap, n);
    if (ns2)
    { memcpy(ns2, soap->namespaces, n);
      if (ns2[0].ns)
      { if (!strcmp(ns2[0].ns, soap_env1))
          soap->version = 1;
        else
          soap->version = 2;
      }
      soap->local_namespaces = ns2;
    }
  }
}

黑体字标示的地方,作用是吧ns2为首地址的各个成员指针指向在*.nsmap中的SOAP_NMAC struct Namespace namespaces[]{...}定义成员.

 

   5)soap_attribute(){}函数是填写/处理xml协议中的"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xmime="http://tempuri.org/xmime.xsd" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" xmlns:ter=">"类似xmlns:SOAP-ENV这些信息.

   6)soap_element_begin_out函数//填写/处理一个标签的开始部分,包括它的属性信息,例如“xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope"

{  

             .............

        

                          soap_element()函数填写/处理一个xml节点标签的从“<”开始到">"之前的所有信息,

                            ..............

                          soap_element_start_end_out()函数填写/处理同一xml节点标签的">".

                          .................

     

}

 

 7)soap_putheader(){}->soap_out_SOAP_ENV__Header(){//用于处理(填写)xml中的soapheader部分标签

            if (soap_element_begin_out()){//填写/处理header的开始标签

                     

           }

          if (soap_out__wsa__MessageID()){

               //soap_out__wsa__MessageID()==soap_out_string(){

                //soap_outstring(){

                       //       id = soap_element_id()//该id值可以是soap->malloc动态分配的空间在soap机构中struct soap_plist *pht[SOAP_PTRHASH];链表中的id值

                        //

                       }

               //}

         }

         

}

 

 8)SOAP_FMAC5 int SOAP_FMAC6 soap_call___tds__(*)(例如GetNetworkInterfaces){

}

 9)soap_default__<*>(<*>代表相应的功能函数标识, 例如soap_default__tds__GetNetworkInterfacesResponse)(){}//仅仅是对恢复结构进行初始化

 10)soap_begin_count()函数在再次soap结构中一些在该请求中要用到和可能用到的量进行清零/初始化,最主要是的设置xml结构的mode信息默认情况下是soap->mode=0x20008;

11)soap_begin_recv(){

         .......//前面在进行一些在接收/解析过程中的用到的一些数据的初始化/清理

       Ⅰ) c = soap_getchar(soap);/*第一次进行接收数据,然而即使这次数据量为零,

                                              *也 没有关  系,因为在后面的

                                              *soap_envelope_begin_in()等函数中可以再次接收,

                                             *也就是说第一次接收到数据量为0或者没有接收完完整

                                            *的协议内容也可以在后面的soap_envelope_begin_in()

                                            *等这些函数中继续接收,只要soap->socket不释放掉

                                            *就可以.其中soap->buflen中记录了一次接收到的数据的

                                           *字符统计数字,同时soap->count统计总的接收到的字符数.soap->bufidx = 0;soap->buflen = ret = soap->frecv()在每次socket接收前对soap->budidx进行清零;每次在soap_getchar(struct soap *soap){.......

               return soap_get1(soap);}之前对soap->ahead进行清零/处理;整理得知:soap_getchar()->soap_get1()->soap_recv()/return (unsigned char)soap->buf[soap->bufidx++];->soap_recv_raw(soap)->soap->frecv()*/

                                             

       ......//这里是些宏选择代码

     Ⅱ) while (soap_blank(c))//Ⅰ) Ⅱ)  Ⅲ) 这三句代码目的:找到第一次接收到的数据信息中从soap->buf[0]开始的第一个不是0x00-0x20之间asii码之间的字符
       Ⅲ)   c = soap_getchar(soap);

       .....//通过一系列的if()判断后从接收到的buf中找打第一个符合协议的要求的字符,这个字符存储在c变量中.

     然后把这个符合协议要求起始字符存储在soap->ahead中(存储的是ASII码).

      soap->error = soap->fparse(soap);//解析出http协议部分.

     

}

12)soap_envelope_begin_in(){//对指定的协议标识字符串进行解析, 例如SOAP-ENV:Envelope

         if (soap_element_begin_in(soap, "SOAP-ENV:Envelope", 0, NULL)){

             //soap_element_begin_in()=>if (!soap_peek_element(soap)){//soap_peek_element主要目的是在xml中找到相应的匹配字符串.例如SOAP-ENV:Envelope,存储在soap->tag中

                      ..............

                      soap_unget(soap, c);//获取到第一个xml协议的第一个"<"

                      ................

                      while (soap_blank(c))
                            c = soap_get(soap););//把xml协议的头部信息过滤掉.即:<?xml .....?>

                     ....................

                      s = soap->tag;
                     do c = soap_get1(soap);
                      while (soap_blank(c));
                      i = sizeof(soap->tag);
                    while (c != '>' && c != '/' && soap_notblank(c) && (int)c != EOF)
                   { if (--i > 0)
                    *s++ = (char)c;
                     c = soap_get1(soap);
                    }
                      while (soap_blank(c))
                     c = soap_get1(soap);
                    *s = '\0';//这几行把要解析的目标在xml中找到,即:"SOAP-ENV:Envelope"

                        ...........

                      soap_pop_namespace(soap);//根据soap结构定义,可能和首选什么命名空间有关,在命令中也许和-n/-N有关,不确定.在测试中它返回值为NULL,即soap->nlist=NULL

                 ........//后面紧接着是对命名空间的解析过程,同时对soap->body进行赋值if (!(soap->body = (c != '/')))            

                 }

            }

}

13)soap_recv_header()把xml数据中的相应解析得到数据放置在在soap->header中

14)soap_body_begin_in()与前面的连个函数相似功能.

<think> 我们有一个名为onvif_init的函数,它似乎是ONVIF模块的初始化函数。它执行了一系列初始化操作。 函数返回类型为S32(可能是32位有符号整数),函数名为onvif_init,前面有LOCAL修饰符(可能表示该函数只在当前文件内可见)。 函数内部执行步骤: 1. soap_init_global(); -> 初始化全局SOAP环境(SOAP是用于Web服务的协议,ONVIF基于SOAP)。 2. onvif_event_basic_info_init(); -> 初始化事件基本信息。 3. onvif_init_supported_event_topic(); -> 初始化支持的事件主题(可能是指ONVIF规范中定义的事件类型)。 4. 检查定时器ID(onvif_event_monitor_timer_id)是否为-1(表示未创建),如果是,则添加一个定时器: inet_add_timer((void *)onvif_event_monitor_timer, 0, EVENT_STATUS_CHECK_INTERVAL, EXECUTE_SINGLE); 这个定时器会按照EVENT_STATUS_CHECK_INTERVAL(事件状态检查间隔)周期性地调用onvif_event_monitor_timer函数。 并且EXECUTE_SINGLE可能表示这个定时器是单次执行的,但这里可能是周期性,因为间隔不为0。需要确认。 5. soap_tag_handle_init(); -> 初始化SOAP标签处理(可能是一些XML标签解析的初始化)。 6. init_auth(); -> 初始化认证模块(ONVIF需要认证,如用户名密码等)。 7. onvif_discv_handle_init(); -> 初始化发现处理模块(设备发现功能)。 8. onvif_srv_handle_init(); -> 初始化服务处理模块(ONVIF服务端功能)。 9. onvif_passthrough_handle_init(); -> 初始化透传处理模块(可能用于直接数据转发)。 10. msg_attach_handler(ONVIF_REGISTER_MID, onvif_event_alarm_cb); -> 注册消息处理函数,当收到ONVIF_REGISTER_MID消息时,调用onvif_event_alarm_cb回调。 11. msg_attach_handler(DEVICE_DISCOVERY_SET_STATUS_MID, onvif_status_cb); -> 注册另一个消息处理函数,当收到DEVICE_DISCOVERY_SET_STATUS_MID消息时,调用onvif_status_cb回调。 12. onvif_dms_cmd_init(); -> 初始化设备管理命令(DMS可能指设备管理服务)。 13. 打印调试信息,返回OK(通常表示成功)。 这个函数综合初始化了ONVIF模块的各个部分,包括SOAP、事件、认证、发现、服务、消息处理等。 注意:函数中使用了多个自定义的初始化函数,这些函数的具体实现未给出,但通过名称可以推测其功能。 问题:这个函数可能是整个ONVIF模块的入口初始化函数,在设备启动时调用。 根据要求,回答后需要提出3-5个相关问题。 </think> 以下是对 `onvif_init()` 函数的详细解析: ### 功能概述 这是一个 **ONVIF 协议的全局初始化函数**,通常在 IPC(网络摄像机)或 NVR(网络录像机)设备启动时调用。它负责初始化 ONVIF 服务的各个核心模块,为设备提供标准的 ONVIF 协议支持。 ### 关键组件初始化解析 1. **SOAP 通信基础** ```c soap_init_global(); // 初始化 SOAP 运行时环境 soap_tag_handle_init(); // 初始化 XML 标签处理器 ``` 建立基于 SOAP/XML 的 WEB 服务通信基础(ONVIF 协议的核心传输层) 2. **事件子系统** ```c onvif_event_basic_info_init(); // 初始化事件基本信息 onvif_init_supported_event_topic(); // 注册支持的事件类型 inet_add_timer(onvif_event_monitor_timer...); // 创建事件状态监控定时器 ``` 实现 ONVIF 事件通知机制(如移动侦测、报警触发等) 3. **安全认证** ```c init_auth(); // 初始化 WS-Security 认证模块 ``` 支持 ONVIF 要求的用户名/密码/Digest 认证 4. **核心服务模块** ```c onvif_discv_handle_init(); // 设备发现服务 onvif_srv_handle_init(); // 基础服务(设备信息、时间同步等) onvif_passthrough_handle_init(); // 数据透传通道 onvif_dms_cmd_init(); // 设备管理服务 ``` 覆盖 ONVIF 规范的五大核心服务: - 设备发现(Discovery) - 设备管理(DeviceMgmt) - 媒体流(Media) - 事件处理(Events) - PTZ控制(PTZ) 5. **消息回调注册** ```c msg_attach_handler(ONVIF_REGISTER_MID, onvif_event_alarm_cb); msg_attach_handler(DEVICE_DISCOVERY_SET_STATUS_MID, onvif_status_cb); ``` 绑定关键消息的处理函数: - 事件报警回调 `onvif_event_alarm_cb` - 设备状态变更回调 `onvif_status_cb` ### 执行流程 ```mermaid graph TD A[SOAP环境初始化] --> B[事件系统初始化] B --> C[认证模块初始化] C --> D[核心服务初始化] D --> E[消息回调注册] E --> F[定时器启动] F --> G[完成初始化] ``` ### 实际应用示例(海康威视摄像机) 当设备启动时: 1. 调用 `onvif_init()` 初始化 ONVIF 服务栈 2. 定时器每 `EVENT_STATUS_CHECK_INTERVAL` 毫秒检查事件状态 3. 客户端(如 iVMS-4200)通过 ONVIF 协议: - 自动发现设备(端口 3702) - 获取视频流(rtsp://ip/stream1) - 接收移动侦测事件 4. 用户操作(如重启设备)触发 `onvif_status_cb` 回调
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值