忙了一个多月,onvif总算告一段落了。这几个星期忙着其他的项目,也没有好好整理一下onvif的东西。接下来得好好整理一下自己的项目思路和项目经验,同时将自己的一些心得写出来,希望对人有所帮助。

相信大多数兄弟和我一样,onvif开发,最开始做的就是发现功能。这两天登录onvif的官网看才发现,onvif版本在八月份有更新,已经更新到V2.4了,于是下载最新的版本来进行。代码的生成可以详见我的前一篇文章。V2.4版本新增了一个wsdl文件,现在用于生成源码的文件一共有18个。为了保证全功能,最好一次性生成包含所有功能的源码。然后根据最新生成的源码来实现onvif客户端和服务端的发现功能。

1. 创建onvif_test目录。以下这些源码由最新的gsoap(2.8.16)和最新的onvif的wsdl文件(2.4)生成。(截止2013.09.16)

onvif.h

soapClientLib.c

soapServerLib.c

soapC.c

soapClient.c

soapH.h

soapServer.c

soapStub.h

2.以下文件来自gsoap_2.8.16\gsoap-2.8\gsoap

stdsoap2.c

stdsoap2.h

3.以下文件来自gsoap_2.8.16\gsoap-2.8\gsoap\custom

duration.c

4.生成的soapClientLib.c和soapServerLib.c无实际作用,可直接删除。

5.增加自定义文件:

onvif_server.c   onvif服务端实现代码

onvif_client.c   onvif客户端实现代码

onvif_server_interface.c   onvif服务端接口实现

onvif_function.c  onvif实现函数,公用

onvif_function.h  onvif实现函数,公用

onvif_server.c为服务端的实现代码,主要是定义main函数,服务端主要是监听,并处理和应答消息。

Main函数定义如下:

  1. int main(int argc,char ** argv)
  2. {
  3. printf("[%s][%d][%s][%s] start \n", __FILE__, __LINE__, __TIME__, __func__);
  4. int count = 0;
  5. struct soap ServerSoap;
  6. struct ip_mreq mcast;
  7. soap_init1(&ServerSoap, SOAP_IO_UDP | SOAP_XML_IGNORENS);
  8. soap_set_namespaces(&ServerSoap,  namespaces);
  9. printf("[%s][%d][%s][%s] ServerSoap.version = %d \n", __FILE__, __LINE__, __TIME__, __func__, ServerSoap.version);
  10. if(!soap_valid_socket(soap_bind(&ServerSoap, NULL, ONVIF_LISTEN_PORT, 10)))
  11. {
  12. soap_print_fault(&ServerSoap, stderr);
  13. exit(1);
  14. }
  15. mcast.imr_multiaddr.s_addr = inet_addr("239.255.255.250");
  16. mcast.imr_interface.s_addr = htonl(INADDR_ANY);
  17. if(setsockopt(ServerSoap.master, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mcast, sizeof(mcast)) < 0)
  18. {
  19. printf("setsockopt error! error code = %d,err string = %s\n",errno,strerror(errno));
  20. return 0;
  21. }
  22. for(;;)
  23. {
  24. if(soap_serve(&ServerSoap))
  25. {
  26. soap_print_fault(&ServerSoap, stderr);
  27. }
  28. soap_destroy(&ServerSoap);
  29. soap_end(&ServerSoap);
  30. //客户端的IP地址
  31. printf("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));
  32. count++;
  33. }
  34. //分离运行时的环境
  35. soap_done(&ServerSoap);
  36. return 0;
  37. }

onvif_server_interface.c   此文件用来定义所有服务端需要填充的接口。这里我们填充__wsdd__Probe接口即可,其他赞不支持的接口可以用宏统一处理。

__wsdd__Probe的填充如下:

  1. SOAP_FMAC5 int SOAP_FMAC6  __wsdd__Probe(struct soap* soap, struct wsdd__ProbeType *wsdd__Probe)
  2. {
  3. #define MACH_ADDR_LENGTH 6
  4. #define INFO_LENGTH 512
  5. #define LARGE_INFO_LENGTH 1024
  6. #define SMALL_INFO_LENGTH 512
  7. printf("[%d] __wsdd__Probe start !\n", __LINE__);
  8. unsigned char macaddr[6] = {0};
  9. char _IPAddr[INFO_LENGTH] = {0};
  10. char _HwId[1024] = {0};
  11. wsdd__ProbeMatchesType ProbeMatches;
  12. ProbeMatches.ProbeMatch = (struct wsdd__ProbeMatchType *)soap_malloc(soap, sizeof(struct wsdd__ProbeMatchType));
  13. ProbeMatches.ProbeMatch->XAddrs = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  14. ProbeMatches.ProbeMatch->Types = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  15. ProbeMatches.ProbeMatch->Scopes = (struct wsdd__ScopesType*)soap_malloc(soap,sizeof(struct wsdd__ScopesType));
  16. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties = (struct wsa__ReferencePropertiesType*)soap_malloc(soap,sizeof(struct wsa__ReferencePropertiesType));
  17. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters = (struct wsa__ReferenceParametersType*)soap_malloc(soap,sizeof(struct wsa__ReferenceParametersType));
  18. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName = (struct wsa__ServiceNameType*)soap_malloc(soap,sizeof(struct wsa__ServiceNameType));
  19. ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType = (char **)soap_malloc(soap, sizeof(char *) * SMALL_INFO_LENGTH);
  20. ProbeMatches.ProbeMatch->wsa__EndpointReference.__any = (char **)soap_malloc(soap, sizeof(char*) * SMALL_INFO_LENGTH);
  21. ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);
  22. ProbeMatches.ProbeMatch->wsa__EndpointReference.Address = (char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  23. netGetMac("eth4", macaddr); //eth0  根据实际情况填充
  24. macaddr[0]=0x01;macaddr[1]=0x01;macaddr[2]=0x01;macaddr[3]=0x01;macaddr[4]=0x01;macaddr[5]=0x01;
  25. sprintf(_HwId,"urn:uuid:2419d68a-2dd2-21b2-a205-%02X%02X%02X%02X%02X%02X",macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4], macaddr[5]);
  26. unsigned int localIp = 0;
  27. netGetIp("eth4", &localIp); //eth0 根据实际情况填充
  28. sprintf(_IPAddr, "http://%s/onvif/device_service", inet_ntoa(*((struct in_addr *)&localIp)));
  29. printf("[%d] _IPAddr ==== %s\n", __LINE__, _IPAddr);
  30. ProbeMatches.__sizeProbeMatch = 1;
  31. ProbeMatches.ProbeMatch->Scopes->__item =(char *)soap_malloc(soap, 1024);
  32. memset(ProbeMatches.ProbeMatch->Scopes->__item,0,sizeof(ProbeMatches.ProbeMatch->Scopes->__item));
  33. //Scopes MUST BE
  34. strcat(ProbeMatches.ProbeMatch->Scopes->__item, "onvif://www.onvif.org/type/NetworkVideoTransmitter");
  35. ProbeMatches.ProbeMatch->Scopes->MatchBy = NULL;
  36. strcpy(ProbeMatches.ProbeMatch->XAddrs, _IPAddr);
  37. strcpy(ProbeMatches.ProbeMatch->Types, wsdd__Probe->Types);
  38. printf("wsdd__Probe->Types=%s\n",wsdd__Probe->Types);
  39. ProbeMatches.ProbeMatch->MetadataVersion = 1;
  40. //ws-discovery规定 为可选项
  41. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__size = 0;
  42. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceProperties->__any = NULL;
  43. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__size = 0;
  44. ProbeMatches.ProbeMatch->wsa__EndpointReference.ReferenceParameters->__any = NULL;
  45. ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);
  46. //ws-discovery规定 为可选项
  47. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.PortType[0], "ttl");
  48. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__item = NULL;
  49. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->PortName = NULL;
  50. ProbeMatches.ProbeMatch->wsa__EndpointReference.ServiceName->__anyAttribute = NULL;
  51. ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0] = (char *)soap_malloc(soap, sizeof(char) * SMALL_INFO_LENGTH);
  52. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__any[0], "Any");
  53. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.__anyAttribute, "Attribute");
  54. ProbeMatches.ProbeMatch->wsa__EndpointReference.__size = 0;
  55. strcpy(ProbeMatches.ProbeMatch->wsa__EndpointReference.Address, _HwId);
  56. soap->header->wsa__To = "http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous";
  57. soap->header->wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatches";
  58. soap->header->wsa__RelatesTo = (struct wsa__Relationship*)soap_malloc(soap, sizeof(struct wsa__Relationship));
  59. soap->header->wsa__RelatesTo->__item = soap->header->wsa__MessageID;
  60. soap->header->wsa__RelatesTo->RelationshipType = NULL;
  61. soap->header->wsa__RelatesTo->__anyAttribute = NULL;
  62. soap->header->wsa__MessageID =(char *)soap_malloc(soap, sizeof(char) * INFO_LENGTH);
  63. strcpy(soap->header->wsa__MessageID,_HwId+4);
  64. if (SOAP_OK == soap_send___wsdd__ProbeMatches(soap, "http://", NULL, &ProbeMatches))
  65. {
  66. printf("send ProbeMatches success !\n");
  67. return SOAP_OK;
  68. }
  69. printf("[%d] soap error: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  70. return soap->error;;
  71. }

onvif_client.c   onvif客户端实现代码,主要是定义客户端的main函数:

Main定义如下:

  1. int main()
  2. {
  3. printf("[%s][%d][%s][%s] start \n", __FILE__, __LINE__, __TIME__, __func__);
  4. int result = 0;
  5. wsdd__ProbeType req;
  6. struct __wsdd__ProbeMatches resp;
  7. wsdd__ScopesType sScope;
  8. struct SOAP_ENV__Header header;
  9. struct soap *soap;
  10. soap = soap_new();
  11. if(NULL == soap )
  12. {
  13. printf("sopa new error\r\n");
  14. return -1;
  15. }
  16. soap->recv_timeout = 10;
  17. soap_set_namespaces(soap, namespaces);
  18. soap_default_SOAP_ENV__Header(soap, &header);
  19. uuid_t uuid;
  20. char guid_string[100];
  21. uuid_generate(uuid);
  22. uuid_unparse(uuid, guid_string);
  23. header.wsa__MessageID = guid_string;
  24. header.wsa__To = "urn:schemas-xmlsoap-org:ws:2005:04:discovery";
  25. header.wsa__Action = "http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe";
  26. soap->header = &header;
  27. soap_default_wsdd__ScopesType(soap, &sScope);
  28. sScope.__item = "";
  29. soap_default_wsdd__ProbeType(soap, &req);
  30. req.Scopes = &sScope;
  31. req.Types = ""; //"dn:NetworkVideoTransmitter";
  32. int i = 0;
  33. result = soap_send___wsdd__Probe(soap, MULTICAST_ADDRESS, NULL, &req);
  34. while(result == SOAP_OK)
  35. {
  36. result = soap_recv___wsdd__ProbeMatches(soap, &resp);
  37. if(result == SOAP_OK)
  38. {
  39. if(soap->error)
  40. {
  41. printf("soap error 1: %d, %s, %s\n", soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  42. result = soap->error;
  43. }
  44. else
  45. {
  46. printf("guog *********************************************\r\n");
  47. if(soap->header->wsa__MessageID)
  48. {
  49. printf("MessageID   : %s\r\n", soap->header->wsa__MessageID);
  50. }
  51. if(soap->header->wsa__RelatesTo && soap->header->wsa__RelatesTo->__item)
  52. {
  53. printf("RelatesTo   : %s\r\n", soap->header->wsa__RelatesTo->__item);
  54. }
  55. if(soap->header->wsa__To)
  56. {
  57. printf("To          : %s\r\n", soap->header->wsa__To);
  58. }
  59. if(soap->header->wsa__Action)
  60. {
  61. printf("Action      : %s\r\n", soap->header->wsa__Action);
  62. }
  63. for(i = 0; i < resp.wsdd__ProbeMatches->__sizeProbeMatch; i++)
  64. {
  65. printf("__sizeProbeMatch        : %d\r\n", resp.wsdd__ProbeMatches->__sizeProbeMatch);
  66. printf("wsa__EndpointReference       : %p\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference);
  67. printf("Target EP Address       : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->wsa__EndpointReference.Address);
  68. printf("Target Type             : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Types);
  69. printf("Target Service Address  : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->XAddrs);
  70. printf("Target Metadata Version : %d\r\n", resp.wsdd__ProbeMatches->ProbeMatch->MetadataVersion);
  71. if(resp.wsdd__ProbeMatches->ProbeMatch->Scopes)
  72. {
  73. printf("Target Scopes Address   : %s\r\n", resp.wsdd__ProbeMatches->ProbeMatch->Scopes->__item);
  74. }
  75. }
  76. }
  77. }
  78. else if (soap->error)
  79. {
  80. printf("[%d] soap error 2: %d, %s, %s\n", __LINE__, soap->error, *soap_faultcode(soap), *soap_faultstring(soap));
  81. result = soap->error;
  82. }
  83. }
  84. soap_destroy(soap);
  85. soap_end(soap);
  86. soap_free(soap);
  87. printf("[%d] guog discover over !\n", __LINE__);
  88. return result;
  89. }

6.将wsdd.nsmap改为nsmap.h,并删除其余的*.nsmap(都一样)

7.编写makefile文件。注意在makefile中打开开关DEBUG,以便跟踪日志。

8.tcpdump为gcc环境的抓包工具,调试的时候用。

make编译通过,运行,客户端发现功能ok;

但是服务端的发现功能却不行;别急,这是由于SOAP的版本问题;soap的版本是根据命名空间来自动确定的;在soap结构体的version字段表示soap版本;

以下命名空间表示SOAP1.1版本:

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},

{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL}, //1.1

以下命名空间表示SOAP1.2版本:

{"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},

{"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},  //1.2

注意确定自己当前的命名空间。我们用SOAP1.2版本才能被测试工具发现(ONVIF Device Test Tool version 13.06)。

不清楚可以查看soap_set_namespaces接口和soap_set_local_namespaces接口;

于是将nsmap.h中的命名空间前两行改为:

{"SOAP-ENV", "http://www.w3.org/2003/05/soap-envelope", "http://schemas.xmlsoap.org/soap/envelope/", NULL},

{"SOAP-ENC", "http://www.w3.org/2003/05/soap-encoding", "http://schemas.xmlsoap.org/soap/encoding/", NULL},  //1.2

再编译运行,发现功能ok。

最后,将所用的工具和源码提供给大家,大家根据需要下载。

onvif测试工具V13.06:http://download.csdn.net/detail/u011597695/6288593

gsoap 2.8.16版本: http://download.csdn.net/detail/u011597695/6288615

onvif v2.4版本的wsdl文件:http://download.csdn.net/detail/u011597695/6288627

onvif v2.4版本的wsdl文件(适于离线生成源码):http://download.csdn.net/detail/u011597695/6288647

onvif源代码V2.4:http://download.csdn.net/detail/u011597695/6288663

from:http://blog.csdn.net/love_xjhu/article/details/11821037

最新文章

  1. wpf 客户端 添加qq客服咨询
  2. 删除Tomcat服务及其它注意
  3. iOS NSDate本地化
  4. SVM与LR的区别以及SVM的优缺点
  5. HDU 5908 Abelian Period(暴力+想法题)
  6. MQTT V3.1----publish解读
  7. ubuntu13.04下安装jdk7
  8. CSS3中媒体查询,更换样式表
  9. DetailsView的添加,修改,删除,查询
  10. hdu 4586 Play the Dice
  11. 如何查看你的 memcached 的状态
  12. Jar包可执行??
  13. ACM HDU 1021 Fibonacci Again
  14. while 、do...while 、for
  15. fiddler4手机抓包
  16. 微信小程序购物车产品计价
  17. hdf 5文件格式及python中利用h5py模块读写h5文件
  18. spring的基于XML方式的属性注入
  19. BZOJ4764弹飞大爷——LCT
  20. python接口自动化测试二:常用操作

热门文章

  1. 9 hbase源码系列(九)StoreFile存储格式
  2. Nutch1.6学习笔记
  3. Intel Media SDK 性能測试
  4. ios学习:swift中实现分享到微博、facebook,twitter等
  5. MKVToolNix v8.2
  6. 1.Apache Axis配置文件WSDD详解
  7. net.sf.json Maven依赖配置
  8. Mysql基础第二部分,针对以后python使用
  9. HDU 5379 Mahjong tree dfs+组合数学
  10. Firewalld 用法解析