打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
onvif服务器篇之设备发现(onvifdiscover)

一、设备发现的机制

从ONVIF的官方文档中可以了解到,客户端在UDP协议下,向网段内的组播地址239.255.255.250,端口3702,不断地向四周发送Probe消息探针,而网段内的服务器在接收到Probe这个探测消息后,通过回复ProbeMatch消息让客户端接收,从而让客户端识别到服务器。

所以服务器端就需要创建一个UDP协议的socket,去监听239.255.255.250:3702,接收到客户端的Probe探针后,进行响应,从而让客户端识别到onvif服务器。


二、编程环境

1. onvif服务器框架代码

服务器的框架代码在上一篇博客中已经实现,详情可以参考《onvif服务器篇之onvif 服务器框架的搭建》

2.onvifServerInterface.c接口函数

在框架代码的基础上,我们需要创建一个onvifServerInterface.c文件,去实现一些接口函数,这些接口函数来自于各个wsdl文件对应模块的接口,但是这些接口需要我们自己去实现,这是ONVIF的实现机制,哪怕没有调用到,也要给一个空函数体,这一点在《onvif服务器篇之onvif 服务器框架的搭建》最后一段中有交代。

3.main.c主函数

main.c实现的功能是在用来建立socket去监听239.255.255.250,端口3702,这里在前面设备发现的机制中已经有提到。


三、代码实现

1.onvifServerInterface.c的实现

#include "wsaapi.h"
#include "soapH.h"
#include "soapStub.h"
#include "wsdd.nsmap"

SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Hello(struct soap* soap, struct wsdd__HelloType *wsdd__Hello)
{
 
	return 0;
}
 
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Bye(struct soap* soap, struct wsdd__ByeType *wsdd__Bye)
{
 
	return 0;
}
 
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__ProbeMatches(struct soap* soap, struct wsdd__ProbeMatchesType *wsdd__ProbeMatches)
{

    return 0;
}
 
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__Resolve(struct soap* soap, struct wsdd__ResolveType *wsdd__Resolve)
{
 
	return 0;
}
 
SOAP_FMAC5 int SOAP_FMAC6 __wsdd__ResolveMatches(struct soap* soap, struct wsdd__ResolveMatchesType *wsdd__ResolveMatches)
{
 
	return 0;
}
 
#define IP 192.168.20.1					//服务器IP
#define ONVIF_TCP_PORT 5000 			//服务器访问端口(随意设置)

SOAP_FMAC5 int SOAP_FMAC6  __wsdd__Probe(struct soap* soap, struct wsdd__ProbeType *wsdd__Probe)
{
        char scopes_message[] =
            "onvif://www.onvif.org/type/NetworkVideoTransmitter\r\n"
            "onvif://www.onvif.org/Profile/Streaming\r\n"
            "onvif://www.onvif.org/Profile/Q/Operational\r\n"
            "onvif://www.onvif.org/hardware/HD1080P\r\n"
            "onvif://www.onvif.org/name/discover_test\r\n"
            "onvif://www.onvif.org/location/city/GuangZhou\r\n"
            "onvif://www.onvif.org/location/country/China\r\n";

        // response ProbeMatches
        struct wsdd__ProbeMatchesType   wsdd__ProbeMatches = {0};
        struct wsdd__ProbeMatchType     *pProbeMatchType = NULL;
        struct wsa__Relationship        *pWsa__RelatesTo = NULL;

        pProbeMatchType = (struct wsdd__ProbeMatchType*)soap_malloc(soap, sizeof(struct wsdd__ProbeMatchType));
        soap_default_wsdd__ProbeMatchType(soap, pProbeMatchType);
        
        char str_tmp[256] = {0};
        sprintf(str_tmp, "http://%s:%d/onvif/device_service", IP, ONVIF_TCP_PORT);
        pProbeMatchType->XAddrs = soap_strdup(soap, str_tmp);
        if( wsdd__Probe->Types && strlen(wsdd__Probe->Types) )
            pProbeMatchType->Types  = soap_strdup(soap, wsdd__Probe->Types);
        else
            pProbeMatchType->Types  = soap_strdup(soap, "dn:NetworkVideoTransmitter tds:Device");

        pProbeMatchType->MetadataVersion = 1;

        // Build Scopes Message
        struct wsdd__ScopesType *pScopes = NULL;
        pScopes = (struct wsdd__ScopesType *)soap_malloc(soap, sizeof(struct wsdd__ScopesType));
        soap_default_wsdd__ScopesType(soap, pScopes);
        pScopes->MatchBy = NULL;
        pScopes->__item  = soap_strdup(soap, scopes_message);
        pProbeMatchType->Scopes = pScopes;

		char g_uuid[64];
		snprintf(g_uuid, 64, "%s", soap_wsa_rand_uuid(soap));
        pProbeMatchType->wsa__EndpointReference.Address = soap_strdup(soap, g_uuid);

        wsdd__ProbeMatches.__sizeProbeMatch = 1;
        wsdd__ProbeMatches.ProbeMatch       = pProbeMatchType;

        // Build SOAP Header
        pWsa__RelatesTo = (struct wsa__Relationship*)soap_malloc(soap, sizeof(struct wsa__Relationship));
        soap_default__wsa__RelatesTo(soap, pWsa__RelatesTo);
        pWsa__RelatesTo->__item = soap->header->wsa__MessageID;
        soap->header->wsa__RelatesTo = pWsa__RelatesTo;
        soap->header->wsa__Action      = soap_strdup(soap, "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches");
        soap->header->wsa__To          = soap_strdup(soap, "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous");

        soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &wsdd__ProbeMatches);

	return SOAP_OK;
}

2.main.c的实现

#include "soapH.h"

#define ONVIF_UDP_IP "239.255.255.250"
#define ONVIF_UDP_PORT 3702

//绑定端口
static SOAP_SOCKET SoapBind(struct soap *pSoap, const char *pIp, bool flag)
{
    SOAP_SOCKET sockFD = SOAP_INVALID_SOCKET;
    if (flag)
    {
        sockFD = soap_bind(pSoap, ONVIF_UDP_IP, pSoap->port, 10);
        if (soap_valid_socket(sockFD))
        {
            printf("%s:%s:%d flag = %d, sockFD = %d, pSoap->master = %d\n", __FILE__, __func__, __LINE__, flag, sockFD, pSoap->master);
        }
        else
        {
            printf("%s:%s:%d flag = %d\n", __FILE__, __func__, __LINE__, flag);
            soap_print_fault(pSoap, stderr);
        }
    }
    else
    {
        sockFD = soap_bind(pSoap, pIp, pSoap->port, 10);
        if (soap_valid_socket(sockFD))
            printf("%s:%s:%d flag = %d, sockFD = %d, pSoap->master = %d\n", __FILE__, __func__, __LINE__, flag, sockFD, pSoap->master);
        else
        {
            printf("%s:%s:%d flag = %d\n", __FILE__, __func__, __LINE__, flag);
            soap_print_fault(pSoap, stderr);
        }
    }

    return sockFD;
}


//加入设备组,设备发现
static void *OnvifBeDiscovered(void *arg) {

    printf("[%s][%d][%s][%s] start \n", __FILE__, __LINE__, __TIME__, __func__);

    struct soap UDPserverSoap;
    struct ip_mreq mcast;

    soap_init1(&UDPserverSoap, SOAP_IO_UDP | SOAP_XML_IGNORENS);
    soap_set_namespaces(&UDPserverSoap,  namespaces);

    int m = soap_bind(&UDPserverSoap, NULL, ONVIF_UDP_PORT, 10);
    if(!soap_valid_socket(m))
    {
        soap_print_fault(&UDPserverSoap, stderr);
        exit(1);
    }

    mcast.imr_multiaddr.s_addr = inet_addr(ONVIF_UDP_IP);
    mcast.imr_interface.s_addr = htonl(INADDR_ANY);
    //开启route
    system("route add -net 224.0.0.0 netmask 224.0.0.0 eth0");
    //IP_ADD_MEMBERSHIP用于加入某个多播组,之后就可以向这个多播组发送数据或者从多播组接收数据
    if(setsockopt(UDPserverSoap.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 0;
    }

    int fd = -1;
    while(1)
    {
        fd = soap_accept(&UDPserverSoap);
        if (!soap_valid_socket(fd)) {
            soap_print_fault(&UDPserverSoap, stderr);
            exit(1);
        }
        
        if( soap_serve(&UDPserverSoap) != SOAP_OK )
        {
            soap_print_fault(&UDPserverSoap, stderr);
            printf("soap_print_fault\n");
        }
        
        soap_destroy(&UDPserverSoap);
        soap_end(&UDPserverSoap);
    }
    //分离运行时的环境
    soap_done(&UDPserverSoap);
    pthread_exit(0);
}

int main(int argc,char ** argv)
{
    pthread_t discover = 0;
    pthread_create(&discover, NULL, OnvifBeDiscovered, NULL);
    pthread_join(discover, 0);
    return 0;
}

3. 编译.c文件,生成可执行文件

gcc *.c -o main

生成执行文件之后,直接运行,然后再打开ONVIF Device Manager工具或者ONVIF Device Test Tool工具搜索就成功了。

(注意:服务器和测试工具需要处于同一网段,跨网段的发现需要通过ONVIF代理去实现,这里没有用到代理)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
ONVIF: onvif实现功能和经验
onvif开发总结
gSoap使用笔记
ONVIF协议网络摄像机
linux 编程
自己动手用c语言写一个基于服务器和客户端(TCP)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服