ONVIF之设备搜索

前言

ONVIF规范没有自己定义服务发现框架,而是复用了WS-Discovery标准来实现设备发现,接下来我们先了解一下什么是WS-Discovery。

WS-Discovery简介

WS-Discovery全称Web Services Dynamic Discovery。WS-Discovery可以动态地探测到可用的目标服务,以便进行服务调用,从而解决了传统Web Services调用服务模式要预先知道目标服务地址的问题。
WS-Discovery定义了两种模式:Ad hoc模式Managed模式

  • Ad hoc模式:客户端以多播(multicast)的形式往多播组(multicast group)发送一个Probe(探测)消息搜寻目标服务,在该探测消息中,包含相应的搜寻条件。如果目标服务满足该条件,则直接将响应ProbeMatch消息(服务自身相关的信息,包括地址)回复给客户端。
  • Managed模式:即代理模式。Ad hoc模式有个局限性,只能局限于一个较小的网络。Managed模式就是为了解决这个问题的,在Managed模式下,一个维护所有可用目标服务的中心发现代理(Discovery Proxy)被建立起来,客户端只需要将探测消息发送到该发现代理就可以得到相应的目标服务信息。

生成Guid

以下函数是我自己封装的用于生成guid,也可以使用gSoap的soap_wsa_rand_uuid()函数(在wsaapi.h中)生成guid。

/**
* @description: 生成guid(windows下叫guid,linux下叫uuid),格式为urn:uuid:8-4-4-4-12,由系统随机产生
*
* @brief createGuid
* @param[in][out] cBuf          guid值
* @return bool          返回true表示成功,返回false表示失败
*/
bool OnvifFunc::createGuid(char * cBuf)
{
    GUID guid;
    if (S_OK == ::CoCreateGuid(&guid))
    {
        // 如果guid生成成功,则将其转为字符串,保存在cBuf中
        _snprintf_s(cBuf, 64, 1024
            , "{%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}"
            , guid.Data1
            , guid.Data2
            , guid.Data3
            , guid.Data4[0], guid.Data4[1]
            , guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]
            , guid.Data4[6], guid.Data4[7]
        );
        return true;
    }
    return false;
}

设备搜索

/**
* @description: 发现设备
*
* @brief discoveryDevice
* @param[in][out] discoveryRetVec           搜索到的设备信息
* @param[in] IPAddr                 本机IP地址
* @return bool          返回true表示成功,其余查看soap错误码
*/
bool OnvifFunc::discoveryDevice(std::vector<DISCOVERYRET>& discoveryRetVec, std::string IPAddr)
{
    char cBuf[64] = { 0 };
    int iRet = createGuid(cBuf);    
    if (iRet)
    {
        DISCOVERYRET discoveryRet;
        // 初始化soap
        struct soap soap;
        soap_set_mode(&soap, SOAP_C_UTFSTRING);
        wsddProxy  discoveryDev(&soap);
        // 绑定IP地址
        struct in_addr if_req;
        inet_pton(AF_INET, IPAddr.c_str(), static_cast<void *>(&if_req));   // 将点分十进制转换为二进制整数
        discoveryDev.soap->ipv4_multicast_if = static_cast<char *>(soap_malloc(discoveryDev.soap, sizeof(in_addr)));
        memset(discoveryDev.soap->ipv4_multicast_if, 0, sizeof(in_addr));
        memcpy(discoveryDev.soap->ipv4_multicast_if, (char *)&if_req, sizeof(if_req));
        // 设置超时(超过指定时间没有数据就退出)
        discoveryDev.soap->recv_timeout = SOAP_SOCK_TIMEOUT;
        discoveryDev.soap->send_timeout = SOAP_SOCK_TIMEOUT;
        discoveryDev.soap->connect_timeout = SOAP_SOCK_TIMEOUT;
        // 初始化soap描述消息头
        discoveryDev.soap_header(cBuf, NULL, NULL, NULL, NULL, WSA_TO, WSA_ACTION, NULL, NULL, 
            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
        // 设置寻找的设备的范围和类型,二者至少设定一个,否则可能收到非ONVIF设备,出现异常
        struct wsdd__ScopesType scope;      // 用于描述查找哪类的Web服务
        soap_default_wsdd__ScopesType(discoveryDev.soap, &scope);
        scope.__item = SOAP_ITEM;       // 设置寻找设备的范围

        struct wsdd__ProbeType probe;
        soap_default_wsdd__ProbeType(discoveryDev.soap, &probe);
        probe.Scopes = &scope;
        probe.Types = SOAP_TYPES;       // 设置寻找设备的类型
                
        iRet = discoveryDev.send_Probe(SOAP_MCAST_ADDR, NULL, &probe);      // 向组播地址广播Probe消息

        if (iRet != SOAP_OK)
        {
            //清除变量
            discoveryDev.destroy();
            return false;
        }
        else
        {
            // 开始循环接收设备发送过来的消息
            while (1)
            {
                struct __wsdd__ProbeMatches tmp;
                // 接收ProbeMatches,成功返回SOAP_OK 
                iRet = discoveryDev.recv_ProbeMatches(tmp);
                if (iRet != SOAP_OK)
                {
                    break;
                }
                else
                {
                    // 将接收到的数据存入结构体     
                    discoveryRet.deviceXAddrs = tmp.wsdd__ProbeMatches->ProbeMatch->XAddrs;
                    discoveryRet.ulMetadataVersion = tmp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion;
                    discoveryRet.Types = tmp.wsdd__ProbeMatches->ProbeMatch->Types;
                    discoveryRet.Address = tmp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address;
                    discoveryRet.Item = tmp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item;
                    discoveryRetVec.push_back(discoveryRet);
                }
            }
        }
        //清除变量
        discoveryDev.destroy();
        return true;
    }
    return false;
}

特别注意:网上99.99%的中文ONVIF教程在讲解ONVIF设备发现功能时,都没有在代码中体现本机IP地址绑定(包括笔者文末参考中的那篇博客),没有绑定本机IP将会搜索不到设备。

上述代码均为核心代码。

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,497评论 18 139
  • 简介 用简单的话来定义tcpdump,就是:dump the traffic on a network,根据使用者...
    保川阅读 5,934评论 1 13
  • Guide to BluetoothSecurity原文 本出版物可免费从以下网址获得:https://doi.o...
    公子小水阅读 7,824评论 0 6
  • 很实用的编程英语词库,共收录一千五百余条词汇。 第一部分: application 应用程式 应用、应用程序app...
    春天的蜜蜂阅读 1,328评论 0 22
  • 我是很爱下雨天的。为什么不爱呢?如果再给我一床干爽的被子,一个大大的窗子还有一杯暖暖的茶……啊,光想想就舒...
    雪糕老祖阅读 453评论 0 2