ONVIF+BOA文档

本文详细介绍了如何使用gSoap工具和BOA服务器实现ONVIF标准的代理技术,包括ONVIF文档的生成、设备扫描功能的实现以及与ONVIF Test Tool工具的集成。通过此教程,读者可以了解如何在自己的服务器上集成ONVIF功能,以提供设备发现和控制等服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ONVIF+BOA文档

http://blog.sina.com.cn/s/blog_b65e8d3d0102v4c4.html

一、     准备工作:

首先需要从网上下载gSoap工具、纯净的BOA代码,并且解压gSoap压缩包

二、     ONVIF:

1.     生成.h文件的过程:

gSoap支持linux、mac和window系统,进入到我们刚刚解压后生成的gSoap目录中的bin目录中的相应的目录中(其中每个目录中都有两个文件wsdl2h和soapcpp2两个工具),此时我们可以通过网络自动生成onvif.h文件或者把我们需要的所有的wsdl文件已经下载到了本地。

网络:

wsdl2h -sck-oonvif.h -c -s -t .\typemap.dathttp://www.onvif.org/onvif/ver10/device/wsdl/devicemgmt.wsdl http://www.onvif.org/onvif/ver10/event/wsdl/event.wsdl http://www.onvif.org/onvif/ver10/display.wsdl http://www.onvif.org/onvif/ver10/deviceio.wsdl http://www.onvif.org/onvif/ver20/imaging/wsdl/imaging.wsdl http://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl http://www.onvif.org/onvif/ver20/ptz/wsdl/ptz.wsdl  http://www.onvif.org/onvif/ver10/receiver.wsdl http://www.onvif.org/onvif/ver10/recording.wsdl  http://www.onvif.org/onvif/ver10/search.wsdl http://www.onvif.org/onvif/ver10/network/wsdl/remotediscovery.wsdl http://www.onvif.org/onvif/ver10/replay.wsdl http://www.onvif.org/onvif/ver20/analytics/wsdl/analytics.wsdl http://www.onvif.org/onvif/ver10/analyticsdevice.wsdl  http://www.onvif.org/onvif/ver10/schema/onvif.xsd  http://www.onvif.org/ver10/actionengine.wsdl

此时可能很慢有时会失败

离线:

wsdl2h -sck -t typemap.dat  -o onvif.hanalytics.wsdlanalyticsdevice.wsdldevicemgmt.wsdldisplay.wsdlevent.wsdlimaging.wsdlmedia.wsdlptz.wsdlreceiver.wsdlrecording.wsdlremotediscovery.wsdlreplay.wsdlsearch.wsdldeviceio.wsdl

这一步你会发现生成速度非常慢,还会提示找不到onvif.xsd,速度慢得原因是wsdl2h会根据wsdl中引用去网上下载一下xsd和wsdl文件,我们可以将这些文件下载到本地,然后修改wsdl中的路径。

修改之前schemaLocation是一个url,如果你放的和你onvif的wsdl文件相同的目录中,这样写就ok了,如果不是,可以写上相对路径。

2.     生成代码

soapcpp2 -2 -L -c -x -d ../  -I /opt/nfshost/gsoap-2.8/gsoap:/opt/nfshost/gsoap-2.8/gsoap/import/:/opt/nfshost/gsoap-2.8/gsoap/custom/  onvif.h

生成代码时需要依靠部分其他文件所以我们用-I指定目录,根据你的实际情况修改上面红色字

生成的过程中会出现SOAP_ENV__Fault重复定义,注视掉soapSub.h中得内容就行了

好了,我们的代码已经生成。

 

       修改任意一个后缀名字为.nsmap的文件为nsmap.h(所有的.nsmap文件中的内容都是相同的)

       并且拷贝gsoap/custom/duration.c、gsoap/stdsoap2.c、gsoap/stdsoap2.h文件到工程中

3.     实现接口:

在soapStub.h中为我们定义了的函数,我们必须要实现,当然不是要一下子写完,你可以写个空的函数,新建一个c文件,将函数实现。

查找soapStub.h中的Server-Side Operations 注释后面的所有函数都需要我们给出实现(一直到soap_server开头的函数为止)

 

 

 

Probe函数是用来实现设备扫描的,实现如下:

SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Probe(struct soap* soap, structwsdd__ProbeType *wsdd__Probe)

{

       #define MACH_ADDR_LENGTH 6

       #define INFO_LENGTH 512

       #define LARGE_INFO_LENGTH 1024

       #define SMALL_INFO_LENGTH 512

      

       printf("[%d] __wsdd__Probe start !\n", __LINE__);

      

       unsigned char macaddr[6] = {0};

       char _IPAddr[INFO_LENGTH] = {0};

       char _HwId[1024] = {0};

      

       wsdd__ProbeMatchesTypeProbeMatches;

       ProbeMatches.ProbeMatch = (structwsdd__ProbeMatchType *)soap_malloc(soap, sizeof(structwsdd__ProbeMatchType));

       ProbeMatches.ProbeMatch->XAddrs = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);

       ProbeMatches.ProbeMatch->Types = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);

       ProbeMatches.ProbeMatch->Scopes = (structwsdd__ScopesType*)soap_malloc(soap,sizeof(structwsdd__ScopesType));

       ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties = (structwsa__ReferencePropertiesType*)soap_malloc(soap,sizeof(structwsa__ReferencePropertiesType));

       ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters = (structwsa__ReferenceParametersType*)soap_malloc(soap,sizeof(structwsa__ReferenceParametersType));

       ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName = (structwsa__ServiceNameType*)soap_malloc(soap,sizeof(structwsa__ServiceNameType));

       ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType = (char **)soap_malloc(soap, sizeof(char *) * SMALL_INFO_LENGTH);

       ProbeMatches.ProbeMatch->wsa__EndpointReference.__any = (char **)soap_malloc(soap, sizeof(char*) * SMALL_INFO_LENGTH);

       ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);

       ProbeMatches.ProbeMatch->wsa__EndpointReference.Address = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);

 

       netGetMac("eth1", macaddr); //eth0  得到IP地址,根据实际情况

macaddr[0]=0x01;macaddr[1]=0x01;macaddr[2]=0x01;macaddr[3]=0x01;macaddr[4]=0x01;macaddr[5]=0x01;

    sprintf(_HwId,"urn:uuid:2419d68a-2dd2-21b2-a205-XXXXXX",macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);

 

 

       unsignedintlocalIp = 0;

       netGetIp("eth1", &localIp); //eth0 得到IP地址,根据实际情况

       sprintf(_IPAddr, "http://%s/onvif/device_service", inet_ntoa(*((structin_addr *)&localIp)));

       printf("[%d] _IPAddr ==== %s\n", __LINE__, _IPAddr);

      

       ProbeMatches.__sizeProbeMatch = 1;

       ProbeMatches.ProbeMatch->Scopes->__item =(char *)soap_malloc(soap, 1024);

memset(ProbeMatches.ProbeMatch->Scopes->__item,0,sizeof(ProbeMatches.ProbeMatch->Scopes->__item)); 

 

       //Scopes MUST BE

       strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/NetworkVideoTransmitter");

 

       ProbeMatches.ProbeMatch->Scopes->MatchBy = NULL;

       strcpy(ProbeMatches.ProbeMatch->XAddrs, _IPAddr);

       strcpy(ProbeMatches.ProbeMatch->Types, wsdd__Probe->Types);

       printf("wsdd__Probe->Types=%s\n",wsdd__Probe->Types);

       ProbeMatches.ProbeMatch->MetadataVersion = 1;

      

       //ws-discovery瑙勫畾涓哄彲閫夐」

    ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__size = 0;

    ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__any = NULL;

  ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__size = 0;

  ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__any = NULL;

      

       ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);

       //ws-discovery瑙勫畾涓哄彲閫夐」

       strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0], "ttl");

       ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__item = NULL;

       ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->PortName = NULL;

ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__anyAttribute = NULL;

       ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);

       strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0], "Any");

       strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute, "Attribute");

       ProbeMatches.ProbeMatch->wsa__EndpointReference.__size = 0;

       strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.Address, _HwId);

      

       soap->header->wsa__To = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";

       soap->header->wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches";

       soap->header->wsa__RelatesTo = (structwsa__Relationship*)soap_malloc(soap, sizeof(structwsa__Relationship));

       soap->header->wsa__RelatesTo->__item = soap->header->wsa__MessageID;

       soap->header->wsa__RelatesTo->RelationshipType = NULL;

       soap->header->wsa__RelatesTo->__anyAttribute = NULL;

 

       soap->header->wsa__MessageID =(char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);

       strcpy(soap->header->wsa__MessageID,_HwId+4);

 

       if (SOAP_OK == soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &ProbeMatches))

       {

              printf("send ProbeMatches success !\n");

              return SOAP_OK;

       }

 

       printf("[%d] soap error: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap)); 

      

       return soap->error;;

}

注释掉soap_wsa_2005,此时,我们的webserver可以编译通过了

三、     ONVIF集成到BOA中

我们在boa的src目录中创建一个onvif的目录把我们与onvif相关的代码放到该目录中

1.     实现设备的扫描功能:

由于onvif的扫描是用UDP(组播)请求的,所以我们需要在boa.c中的main函数中创建一个线程用于应答onvif的设备扫描的应答功能,线程函数的代码如下:

void *hello_thr(void *arg)

    

int count = 0;

struct soap ServerSoap;

structip_mreqmcast;

 

soap_init1(&ServerSoap, SOAP_IO_UDP | SOAP_XML_IGNORENS);

soap_set_namespaces(&ServerSoap,  namespaces);

 

printf("[%s][%d][%s][%s] ServerSoap.version = %d \n", __FILE__, __LINE__, __TIME__, __func__, ServerSoap.version);

 

if(!soap_valid_socket(soap_bind(&ServerSoap, NULL, 3702, 10)))

{

        soap_print_fault(&ServerSoap, stderr);

        exit(1);

}

 

mcast.imr_multiaddr.s_addr = inet_addr("239.255.255.250");

mcast.imr_interface.s_addr = htonl(INADDR_ANY);

 

if(setsockopt(ServerSoap.master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)

{

        printf("setsockopt error! error code = %d,err string = %s\n",errno,strerror(errno));

        return NULL;

}

 

while(1)

{

        if(soap_serve(&ServerSoap))

        {

               fprintf(stderr,"soap----udp fault\n");

               soap_print_fault(&ServerSoap, stderr);

        }

        fprintf(stderr,"soap server----over\n");

        soap_destroy(&ServerSoap);

        soap_end(&ServerSoap);

       //客户端的IP地址

fprintf(stderr,"RECEIVE count %d, connection from IP = %lu.%lu.%lu.%lu socket = %d \r\n",count, ((ServerSoap.ip)>>24)&0xFF, ((ServerSoap.ip)>>16)&0xFF, ((ServerSoap.ip)>>8)&0xFF, (ServerSoap.ip)&0xFF, (ServerSoap.socket));

        count++;

}

//分离运行时的环境

soap_done(&ServerSoap);

return NULL;

}

2.     实现用onvif  Test  Tool工具的其他功能:

Onvif的其他功能是通过TCP(80端口)请求的,所以我们要与我们的boa中获得其他HTTP包时同时获得请求并且判断是否为onvif请求,如果是我们就进入onvifServer中,不是我们就进入boa的http应答中,代码如下:

struct soap* soap;

soap=soap_new();

soap_init(soap);

soap->master = server_s;

soap->socket = server_s;

soap->errmode = 0;

soap->bind_flags = 1;

我们知道boa所有的请求循环是在select_loop函数中得到的,所以我们修改该函数

Void select_loop(intserver_s,struct soap* soap);

并且修改process_requests函数,

Void process_requests(intserver_s,struct soap *soap);

这样就可以每次获得我们的onvif请求

下面我们主要修改process_requests函数(如果是onvif请求则进入onvifserver中进行应答,如果是普通的请求则有boa进行应答)

在process_requests函数内添加:

intOnvifEN = 0;

intlookupindex = 0;

charservice_uri[100] = "";

memset((void*)&soap->peer, 0, sizeof(soap->peer));

soap->socket = SOAP_INVALID_SOCKET;

soap->error = SOAP_OK;

soap->errmode = 0;

soap->keep_alive = 0;

在while(current)中添加

OnvifEN = isOnvif(current->client_stream, service_uri, &lookupindex);

if(OnvifEN == 1)

 {

              //soap->socket = midhnewsock;

              soap->socket = current->fd;

              soap->peer = onvif_remote_addr;

       if (soap_valid_socket(soap->socket))

              {

                     soap->ip = ntohl(soap->peer.sin_addr.s_addr);

                     soap->port = (int)ntohs(soap->peer.sin_port);

                     soap->keep_alive = (((soap->imode | soap->omode) & SOAP_IO_KEEPALIVE) != 0);

              }

 

             

              ONVIF_BUFFER = (char *)soap_malloc(soap, sizeof(current->client_stream));

              strcpy(ONVIF_BUFFER, current->client_stream);//缓冲区在frecv函数中需要把ONVIF_BUFFER中的内容再重新拷贝到soap中

 

              soap_begin_recv(soap);

              if (soap_envelope_begin_in(soap))

              {

                     soap_send_fault(soap);

              }

              if (soap_recv_header(soap))

              {

                     soap_send_fault(soap);

              }

              if (soap_body_begin_in(soap))

              {

                     soap_send_fault(soap);

              }

             

              interrorCode = 0;

              if (errorCode = soap_serve_request(soap))

              {

                     fprintf(stderr, "[onvif]soap_serve_request fail, errorCode %d \n", errorCode);

                     soap_send_fault(soap);

              }

             

              //strcpy(current->client_stream, "");

              memset(current->client_stream, 0, CLIENT_STREAM_SIZE );

             

              soap_dealloc(soap, NULL);

              soap_destroy(soap);      

              soap_end(soap);

              current->status = DONE;

              close(soap->socket);

       }

IsOnvif函数的代码如下:

intisOnvif(char *current_client_stream , char *service_uri, int *lookupindex)

{

      

       char segments[3][100];

       charpost_req[80];

       charservice_name[40];

       intservice_index = 0,ret;

       intindex_post = 0;

       intstream_index = 0;

 

       if (strncmp(current_client_stream, "POST ", 5)==0)

       {

              index_post = 0;

              stream_index = 0;

              while(current_client_stream[stream_index] != '\n' &&current_client_stream[stream_index] != '\r')

              {

                     post_req[index_post++] = current_client_stream[stream_index++];

 

              }

              post_req[index_post] = '\0';

              explodeRequest(post_req, ' ', segments);

              index_post = 1;

              service_index = 0;

              while(segments[1][index_post] != '/' && segments[1][index_post] != '\0')

              {

                     service_name[service_index++] = segments[1][index_post++];

              }

              service_name[service_index] = '\0';

              ret = lookupservices(service_name,lookupindex);

              if(ret)

              {

                     strcpy(service_uri,segments[1]);

              }

              return ret;

       }

       else

       {

              return 0;

       }

 

}

voidexplodeRequest(char *in, char dl, char list[][100])

{

       int i = 0;

       int j = 0;

       int k = 0;

       intlen = strlen(in);

       for(i = 0; i

       {

              if(in[i] == dl)

              {

 

                     *( *(list + j) + k) = 0;

                     j++;

                     k = 0;

              }

              else

              {

                     *( *(list + j) + k) = in[i];

                     k++;

              }

       }

       *(*(list + j) + k) = 0;

       j++;

       if(j < 3)

              **(list + j) = 0;

}

 

 

 

intlookupservices(char *service, int *lookupindex)

{

       int i;

       char lookup[10][30]={"device",

                      "imaging",

                      "media",

                      "custom",

                      "onvif",

                      ""};

//   for(i = 0;lookup[i][0];i++)

       for(i = 0; i<6; i++)

       {

              if(strcasecmp(lookup[i], service) == 0)

              {

                     *lookupindex = i;

                     return 1;

              }

       }

       *lookupindex = -1;

       return 0;

}

 

3.修改boa的Makefile文件:

   把我们的onvif目录中的文件添加到Makefile中,make就可以了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值