服务端的开发相对来说比客户端稍微难一点,也就是给填充相关结构体的时候,需要一点一点的去查阅,验证各个结构中各个成员各自代表什么意思,以及对应的功能需要是那个接口实现,这是开发服务端最头疼的事情。(在开发过程中郁闷了好久,后面是通过搜索工具抓包海康设备来填充相关信息的)开始切入主题了,准备服务端的开发了。

同理需要前面生成的代码,这个时候较之客户端的开发,需要在代码生成的时候之前生成的soapServer.c文件了,当放在客户端测试目录下用makefile编译的时候,你可能会很惊讶,怎么这么多错误,这么多函数报错,而且都是没有定义呢?

别紧张,这些接口就是服务端开发需要实现的!即使开发不需要使用,但是根据onvif协议,也是需要给函数一个实现体的,具体的这些函数就需要看看soapServer.c文件里的soap_serve_request函数,这里我贴出来一部分如下:

  1. ifndef WITH_NOSERVEREQUEST
  2. SOAP_FMAC5 int SOAP_FMAC6 soap_serve_request(struct soap *soap)
  3. {
  4. soap_peek_element(soap);
  5. if (!soap_match_tag(soap, soap->tag, "wsdd:Hello"))
  6. return soap_serve___wsdd__Hello(soap);
  7. if (!soap_match_tag(soap, soap->tag, "wsdd:Bye"))
  8. return soap_serve___wsdd__Bye(soap);
  9. if (!soap_match_tag(soap, soap->tag, "wsdd:Probe"))
  10. return soap_serve___wsdd__Probe(soap);
  11. if (!soap_match_tag(soap, soap->tag, "wsdd:ProbeMatches"))
  12. return soap_serve___wsdd__ProbeMatches(soap);
  13. if (!soap_match_tag(soap, soap->tag, "wsdd:Resolve"))
  14. return soap_serve___wsdd__Resolve(soap);
  15. if (!soap_match_tag(soap, soap->tag, "wsdd:ResolveMatches"))
  16. return soap_serve___wsdd__ResolveMatches(soap);
  17. if (!soap_match_tag(soap, soap->tag, "ns1:GetSupportedActions"))
  18. return soap_serve___ns1__GetSupportedActions(soap);
  19. if (!soap_match_tag(soap, soap->tag, "ns1:GetActions"))
  20. return soap_serve___ns1__GetActions(soap);
  21. if (!soap_match_tag(soap, soap->tag, "ns1:CreateActions"))
  22. return soap_serve___ns1__CreateActions(soap);
  23. if (!soap_match_tag(soap, soap->tag, "ns1:DeleteActions"))
  24. return soap_serve___ns1__DeleteActions(soap);
  25. if (!soap_match_tag(soap, soap->tag, "ns1:ModifyActions"))
  26. return soap_serve___ns1__ModifyActions(soap);
  27. if (!soap_match_tag(soap, soap->tag, "ns1:GetServiceCapabilities"))
  28. .
  29. .
  30. .
  31. //当然了,后来还有很长,很多了,具体实际开发可以根据需要来实现对应的函数体就好了

后面还有很多系列函数,都是在对应了接口中调用了需要服务端实现的接口函数,代码框架只是有申明,没有实现,所以开发服务端的第一步,就是需要根据这里,把所以报错没有实现的函数全部实现掉,但是给一个函数体就好,后期开发再确定需要实现那些功能,再一个一个的接口具体实现,所以接下来就是写代码了,即使是拷贝复制工作,你也会有一种手要断了的赶觉的。我记得当时我就是一个整个下午在ctrl+ v 选中,然后p 粘贴.最后弄完眼睛都花了。

因为每个函数的可以用相同的函数体来实现,所以写一个简单宏来代替是比较方面而且直观的方法,我的实现如下:

  1. #define ONVIF_NOT_IMPLEMENTED_FUNC(soap, namespaces) \
  2. if( namespaces != NULL) \
  3. soap_set_namespaces(soap, namespaces); \
  4. printf("Func: %s, Path: %s \n", __func__, soap->path); \
  5. return soap_receiver_fault_subcode(soap, "test:Action Not Supported", "Test: Not Implemented ", "The requested action is not implemented ");

好了有了前面的准备工作开始写发现函数了,设备端的回复搜索的接口函数为__wsdd__Probe__wsdd__Probe,实现如下:

  1. int SOAP_FMAC6  __wsdd__Probe(struct soap* soap, struct wsdd__ProbeType *wsdd__Probe)
  2. {
  3. printf(" \n ##### Start __wsdd__Probe ##### \n");
  4. char _IPAddr[64] = {0};
  5. char _HwId[256] = {0};
  6. wsdd__ProbeMatchesType ProbeMatches;
  7. ProbeMatches.ProbeMatch = (struct wsdd__ProbeMatchType *)soap_malloc(soap, sizeof(struct wsdd__ProbeMatchType));
  8. memset(ProbeMatches.ProbeMatch, 0,  sizeof(struct wsdd__ProbeMatchType));
  9. ProbeMatches.ProbeMatch->XAddrs = (char *)soap_malloc(soap, sizeof(char) * 256);
  10. memset(ProbeMatches.ProbeMatch->XAddrs, '\0', sizeof(char) * 256);
  11. ProbeMatches.ProbeMatch->Types = (char *)soap_malloc(soap, sizeof(char) * 256);
  12. memset(ProbeMatches.ProbeMatch->Types, '\0', sizeof(char) * 256);
  13. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties = (struct wsa__ReferencePropertiesType*)soap_malloc(soap,sizeof(struct wsa__ReferencePropertiesType));
  14. memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties, 0, sizeof(struct wsa__ReferencePropertiesType));
  15. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters = (struct wsa__ReferenceParametersType*)soap_malloc(soap,sizeof(struct wsa__ReferenceParametersType));
  16. memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters, 0, sizeof(struct wsa__ReferenceParametersType));
  17. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName = (struct wsa__ServiceNameType*)soap_malloc(soap,sizeof(struct wsa__ServiceNameType));
  18. memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName, 0, sizeof(struct wsa__ServiceNameType));
  19. ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType = (char **)soap_malloc(soap, sizeof(char *) * 256);
  20. memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType, 0, sizeof(char *) * 256);
  21. ProbeMatches.ProbeMatch->wsa__EndpointReference.__any = (char **)soap_malloc(soap, sizeof(char*) * 256);
  22. memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.__any, 0, sizeof(char*) * 256);
  23. ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute = (char *)soap_malloc(soap, sizeof(char) * 256);
  24. memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute, 0,  sizeof(char) * 256);
  25. ProbeMatches.ProbeMatch->wsa__EndpointReference.Address = (char *)soap_malloc(soap, sizeof(char) * 256);
  26. memset(ProbeMatches.ProbeMatch->wsa__EndpointReference.Address, 0, sizeof(char) * 256);
  27. //这里是一个uid,我在实际开发的过程中是的设备的本身mac地址,这里我取了一个mac地址的地址
  28. strcpy(_HwId, "urn:uuid:20131228-AABB-CCDD-EEFF-010203040506");
  29. //这是是需要回复给给客户端的基本信息.设备的ip地址以及通信端口
  30. sprintf(_IPAddr, "http://%d.%d.%d.%d:%d/onvif/device_service", 192,168,12,103, 8899);
  31. ProbeMatches.__sizeProbeMatch = 1;
  32. ProbeMatches.ProbeMatch->Scopes = (struct wsdd__ScopesType*)soap_malloc(soap, sizeof(struct wsdd__ScopesType) * ProbeMatches.__sizeProbeMatch);
  33. memset(ProbeMatches.ProbeMatch->Scopes, 0, sizeof(struct wsdd__ScopesType) * ProbeMatches.__sizeProbeMatch);
  34. //Scopes MUST BE
  35. ProbeMatches.ProbeMatch->Scopes->__item =(char *)soap_malloc(soap, 1024);
  36. memset(ProbeMatches.ProbeMatch->Scopes->__item, '\0', 1024);
  37. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/Network_Video_Transmitter ");
  38. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/video_encoder ");
  39. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/audio_encoder ");
  40. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/location/city/CSDN ");
  41. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/name/csder ");
  42. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/hardware/TEST_Onvif ");
  43. ProbeMatches.ProbeMatch->Scopes->MatchBy = NULL;
  44. strcpy(ProbeMatches.ProbeMatch->XAddrs, _IPAddr);
  45. strcpy(ProbeMatches.ProbeMatch->Types, wsdd__Probe->Types);
  46. printf("wsdd__Probe->Types=%s\n",wsdd__Probe->Types);
  47. ProbeMatches.ProbeMatch->MetadataVersion = 1;
  48. //ws-discovery规定 为可选项
  49. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__size = 0;
  50. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__any = NULL;
  51. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__size = 0;
  52. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__any = NULL;
  53. ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_256);
  54. //ws-discovery规定 为可选项
  55. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0], "ttl");
  56. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__item = NULL;
  57. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->PortName = NULL;
  58. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__anyAttribute = NULL;
  59. ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_256);
  60. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0], "Any");
  61. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute, "Attribute");
  62. ProbeMatches.ProbeMatch->wsa__EndpointReference.__size = 0;
  63. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.Address, _HwId);
  64. soap->header->wsa__To = (char *)"http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
  65. soap->header->wsa__Action = (char *)"http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches";
  66. soap->header->wsa__RelatesTo = (struct wsa__Relationship*)soap_malloc(soap, sizeof(struct wsa__Relationship));
  67. soap->header->wsa__RelatesTo->__item = soap->header->wsa__MessageID;
  68. soap->header->wsa__RelatesTo->RelationshipType = NULL;
  69. soap->header->wsa__RelatesTo->__anyAttribute = NULL;
  70. soap->header->wsa__MessageID =(char *)soap_malloc(soap, sizeof(char) * 256);
  71. strcpy(soap->header->wsa__MessageID,_HwId+4); //前面四个字节可以是不需要的
  72. if (SOAP_OK == soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &ProbeMatches))
  73. {
  74. //      printf("send ProbeMatches success !\n");
  75. return SOAP_OK;
  76. }
  77. printf("[%d] soap error: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  78. return soap->error;;
  79. }

搜索的回复函数本分就完成了,现在需要要的工作就是在设备端开启一个udp的socket了。为了不影响设备端其他的业务,所以建议设备端另外开一个线程让socket运行起来,因为这个是一个一直循环的操作了,基本的代码如下:

  1. int Onvif_DeviceDiscovery()
  2. {
  3. struct soap udp_soap;
  4. int retval = -1;
  5. soap_init1(&udp_soap, SOAP_IO_UDP | SOAP_IO_FLUSH);
  6. udp_soap.connect_flags = SO_BROADCAST;
  7. udp_soap.port = 3702;
  8. soap_set_namespaces( &udp_soap, namespaces);
  9. SOAP_SOCKET udp_sock = -1;
  10. udp_soap->omode = SOAP_IO_UDP;
  11. udp_soap->bind_flags = SO_REUSEADDR;
  12. udp_sock = soap_bind(udp_soap, NULL, udp_soap->port, 100);
  13. if( (udp_sock < 0) && (udp_sock == SOAP_INVALID_SOCKET))
  14. {
  15. close(udp_sock);
  16. printf(" soap_bind failed! %s \n", strerror(errno));
  17. return -1;
  18. }
  19. //这个接口设置一些广播的属性值,下面也有实现提出,
  20. retval = udp_add_multicast(&udp_soap);
  21. if(retval != 0 )
  22. {
  23. printf(" udp add multicast failed: %s \n", strerror(errno));
  24. return -1;
  25. }
  26. //每次都是在此循环中接收客户端发过来的广播请求,然后服务端调用__wsdd__Probe函数,返回服务端的一些基本信息
  27. while(1)
  28. {
  29. if( soap_serve( &udp_soap ) != 0)
  30. {
  31. soap_print_fault(&udp_soap, stderr);
  32. }
  33. soap_destroy(&udp_soap);
  34. soap_end( &udp_soap);
  35. }
  36. soap_done(&udp_soap);
  37. return 0;
  38. }
  39. int udp_add_multicast( struct soap* socksoap)
  40. {
  41. //  set a route for multicast traffic
  42. //  这个执行一个系统命令,之前一直无法被搜索到,后来查了资料才知道需要启动下
  43. system("route add -net 224.0.0.0 netmask 224.0.0.0 eth0");
  44. int loop;
  45. int retval = -1;
  46. struct ip_mreq mreqcon;
  47. loop = 1;
  48. //设置组播的属性
  49. retval = setsockopt(socksoap->master, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
  50. if(retval != 0)
  51. {
  52. printf("setsockopt: IP_MULTICAST_LOOP failed! %s\n ", strerror(errno));
  53. return -1;
  54. }
  55. //绑定组播的ip地址
  56. mreqcon.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
  57. mreqcon.imr_interface.s_addr = htonl(INADDR_ANY);
  58. if( (signed int )mreqcon.imr_multiaddr.s_addr == -1)
  59. {
  60. printf("239.255.255.250 not a legal multicast address! %s\n", strerror(errno));
  61. return -1;
  62. }
  63. retval = setsockopt(socksoap->master, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreqcon, sizeof(mreqcon));
  64. if( retval != 0 )
  65. {
  66. printf("setsockopt: IP_ADD_MEMBERSHIP failed! %s\n ", strerror(errno));
  67. return -1;
  68. }
  69. return 0;
  70. }

完成这些代码之后,通过onvif搜索工具,搜索的结果图如下

看到基本信息也就是上面代码中填写了!设备端的发现功能也就实现了!

纵观前后,其实设备端的发现只是在已经有的代码框架基础上操作两步就好!

1 创建socket,搭建广播接收回复服务

2 实现__wsdd__Probe函数!

提供大家一个不错的网站:onvif server

Onvif开发之服务端发现篇的更多相关文章

  1. Onvif开发之服务端成功对接Rtsp视频流篇

    前面篇介绍onvif服务端的发现功能,继续在之前的代码基础上完成一个RTSP流的工作,也就是客户端通过ONVIF协议来预览设备端在这个之前必须确定几个简单的条件1 设备端能被发现2 设备端支持RTSP ...

  2. Delphi XE5通过WebService开发Web服务端和手机客户端

    Delphi XE5通过WebService开发Web服务端和手机客户端介绍 我们开发一个三层的android程序 建立一个webservices  stand-alone vcl applicati ...

  3. 项目二:企业级java电商网站开发(服务端)

    声明:项目源于网络,支持正版教程,学习使用,仅记录在此 项目介绍 企业级java电商网站开发(服务端),模块划分:用户管理,商品管理,商品品类管理,订单管理,订单详情管理,购物车管理,收货地址管理,支 ...

  4. Onvif开发之代码框架生成篇

    看了前一篇的ONVIF的简单介绍应该对它的基本使用都有了一些基本的了解了吧!下面我讲一步分解向大家介绍下如何通过gsoap生成需要的代码,以及代码中需要注意的问题[基于Linux平台 C开发] 生成O ...

  5. 使用Apache CXF开发WebServices服务端、客户端

    在前一篇的博客中,我使用Xfire1.x来开发了WebServies的服务端. 但是如果你访问Apache的官网,可以看到xfire已经被合并了. 最新的框架叫做CXF. Apache CXF = C ...

  6. cocos2d-x开发:服务端基础库封装

    元旦前面几天都在忙着面试,随后的几天也就一直在做服务端基础库开发方面的工作.对于服务端开发,是很久之前的事情了.那时候我还在大学读书,一直都是在倒腾服务端开发方面的东西,毕业后参加公司工作就是一直从事 ...

  7. 转:: 刺鸟:用python来开发webgame服务端(2)

    来源:http://ciniao.me/article.php?id=10 --------------- 刺鸟原创文章,转载请注明出处    就在刚才,我们用基于python下的Twisted库写了 ...

  8. iOS推送小结(证书的生成、客户端的开发、服务端的开发)

    1.推送过程简介 1.1.App启动过程中,使用UIApplication::registerForRemoteNotificationTypes函数与苹果的APNS服务器通信,发出注册远程推送的申请 ...

  9. Ajax开发中服务端Response的Content-Type

    转自http://www.cnblogs.com/hyl8218/archive/2010/03/10/1681484.html ajax开发中在请求服务器端的响应时, 对于每一种返回类型 规范的做法 ...

随机推荐

  1. 解析UML用例图中include与extend的区别

    UML用例图有很多值得学习的地方,这里向大家简单介绍一下UML用例图中include与extend的区别,希望本文的介绍对你有所帮助. 本文和大家重点讨论一下UML用例图中include与extend ...

  2. 【DNN发布包解释】package 包裹

    package 包裹 owner 主人 dependency 附属国 azureCompatible 天青兼容 releaseNotes  发行说明 license 许可证 CoreVersion 核 ...

  3. ajax无刷新翻页后,jquery失效问题的解决

    例如 $(".entry-title a").click(function () {   只对第一页有效, 修改为 $(document).on('click', ".e ...

  4. js中字符串下划线转为驼峰

    function camelCase(string){ // Support: IE9-11+ return string.replace( /-([a-z])/g, function( all, l ...

  5. 二、Fast-R-CNN

    一.概括 Fast R-cnn的主要亮点有:Fast R-CNN将借助多任务损失函数,将物体识别和位置修正合成到一个网络中,不再对网络进行分步训练,不需要大量内存来存储训练过程中特征的数据:用RoI层 ...

  6. tf.cast(ndarray,dtype)

    转化为指定的类型,一般是将bool类型转化为其他的数据类型,例如:tf.float32

  7. [JSOI2008]火星人 hash+splay

    题目描述: 现在,火星人定义了一个函数 LCQ(x, y)LCQ(x,y),表示:该字符串中第 xx 个字符开始的字串,与该字符串中第 yy 个字符开始的字串,两个字串的公共前缀的长度.比方说,LCQ ...

  8. ajax发送请求的数据类型

    1.如果要传给后台的是json形式的数据 2.如果要传给后台的是formdata形式的数据

  9. php八大设计模式之工厂模式

    简单点来说,就是用到什么类,就去实例化对应的类.比如:php 可能连接 mysql,可能连接 sqlserver,也可能是 oracle 数据库,可以动态的去链接. 书籍<php权威编程> ...

  10. C++输入流

    输出流基本概念  输出流定义在头文件中.大部分程序都会包含头文件,这个头文件又包含了输入流和输出流头文件.头文件还声明了标准控制台输出流cout.  使用输出流的最简单的方法是使用<<运算 ...