注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

_

_

 
 
 

日志

 
 

[zhuan]ONVIF 客户端简单实现Discovery,实现设备搜索.  

2013-04-19 00:34:51|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

[原]ONVIF 客户端简单实现Discovery,实现设备搜索.

2013-3-18阅读129 评论0

两种方法,一种是使用GSOAP的库WS-Discovery,另一种是直接自己写一个SOCKET多播消息。

第一种解XML和定制XML方便,发送的消息也是标准的Discovery协议,

这种方法能收到XML信息的回应,但解不出来!现在得自己解析这一部分.

第二种就需要自己写XML,对协议了解需要更多点。

第三种直接用onvif WSDL里生成的生成的类型soap_recv___tdn__*********这样的,这个和第一种一样,也还是解不出XML

A: ONVIF GSOAP客户端使用WS-Discovery

使用GSOAP来Discovery,以下是步骤

1:用的到文件(gSOAP WS-Discovery 2.8 Stable手册里有说明)
plugin目录
threads.c
threads.h
wssaapi.c
wssaapi.h
wsddapi.c
wsddapi.h
import目录
wsdd.h
2:用WS目录里的WS-Discovery.wsdl生成代码(当然用ONVIF的remotediscovery也可以,只是产生的就很大了)
./wsdl2h -cgye -o discovery.h -t WS-typemap.dat WS-Discovery.wsdl
./soapcpp2 -C -c -2 -n -pdiscovery discovery.h -I../import
3:一些代码的修改
第2步完成的会生成一些代码,需要改一下 wsddapi.h里的一个头文件的引用
Wsddapi.h 和 wsaapi.h 里有一个 #include "soapH.h",soapH是我们默认生成的名字,因为第二步我改了 生成代码文件的名字,改成discovery了,就是那个 soapcpp2 -n选项
所以需要 Wsddap.h #include "soapH.h"改成 #include "discoveryH.h"
还改了生成文件:discoveryStub.h里的 SOAP_NAMESPACE_OF_wsdd
原来的:
#define SOAP_NAMESPACE_OF_wsdd "http://docs.oasis-open.org/ws-dd/ns/discovery/2009/01"
改成:

#define SOAP_NAMESPACE_OF_wsdd "http://schemas.xmlsoap.org/ws/2005/04/discovery"

因为我对照了ONVIF测试工具发的,这个,和上面生成的不一样,就改了一下.
4:WSDD需要自己实现的几个方法
这个在手册gSOAP WS-Discovery 2.8 Stable里也有说:
以下方法:就是相当于,事件处理函数,如,发后了HELLO后,最后会调用wsdd_event_Hello这个方法
void wsdd_event_ProbeMatches(struct soap *soap, unsigned int InstanceId, const char *SequenceId, unsigned int
MessageNumber, const char *MessageID, const char *RelatesTo, struct wsdd__ProbeMatchesType *matches)
{
return;
}
void wsdd_event_ResolveMatches(struct soap *soap, unsigned int InstanceId, const char *SequenceId, unsigned int
MessageNumber, const char *MessageID, const char *RelatesTo, struct wsdd__ResolveMatchType *match)
{
return;
}
void wsdd_event_Hello(struct soap *soap, unsigned int InstanceId, const char *SequenceId, unsigned int MessageNumber,
const char *MessageID, const char *RelatesTo, const char *EndpointReference, const char *Types, const char *Scopes, const
char *MatchBy, const char *XAddrs, unsigned int MetadataVersion)
{
return;
}
void wsdd_event_Bye(struct soap *soap, unsigned int InstanceId, const char *SequenceId, unsigned int MessageNumber, const
char *MessageID, const char *RelatesTo, const char *EndpointReference, const char *Types, const char *Scopes, const char
*MatchBy, const char *XAddrs, unsigned int *MetadataVersion)
{
return;
}
soap_wsdd_mode wsdd_event_Probe(struct soap *soap, const char *MessageID, const char *ReplyTo, const char *Types, const
char *Scopes, const char *MatchBy, struct wsdd__ProbeMatchesType *matches)
{
printf("MessageID:%s",MessageID);
return SOAP_WSDD_MANAGED;
}
soap_wsdd_mode wsdd_event_Resolve(struct soap *soap, const char *MessageID, const char *ReplyTo, const char
*EndpointReference, struct wsdd__ResolveMatchType *match)
{
return SOAP_WSDD_MANAGED;
}
5:在GOSAP里使用
完成以上的内容,应该就可以用了,因为是多播,所以在发送时要设置
soap.connect_flags = SO_BROADCAST;
像下面的一样,在偏译时打开 -DDEBUG,应该在 RECV.LOG目录里就可以看到收到的消息了.
int main(){
struct soap soap;
char *msg_uuid = NULL;
soap_set_namespaces(&soap,namespaces);
soap_init(&soap);
msg_uuid = soap_wsa_rand_uuid(&soap);
soap.connect_flags = SO_BROADCAST;
printf("msg_uuid:%s\n",msg_uuid);
soap_wsdd_Probe(&soap,SOAP_WSDD_MANAGED,SOAP_WSDD_TO_TS,"soap.udp://239.255.255.250:3702",msg_uuid,NULL,DS_TYPES,"",NULL);
for(i = 0;i<10;i++){
soap_recv___wsdd__Probe(&soap,&__wsdd__probe_recv);
sleep(1);
}
soap_destroy(&soap);
soap_end(&soap);
soap_done(&soap);

}

收到的是一个XML信息,可以定义一个GSOAP的一个回调,如下:

int recv_callback(struct soap *gsoap,char *xml,int len){
printf("xml:%s\n",xml);
return 0;
}

soap.frecv = recv_callback;

或者,直接调用soap_wsdd_Probe后读 soap.buff

以上的过程,事后记录,可能会少了一些细节。
soap_wsdd_Probe是填充BODY和HEADER的内容,而soap_send___wsdd__Probe就是把BUFF发送出去,有的朋友直接调用了soap_send___wsdd__Probe,所以发送的XML就是空的body.

B: 自己写SOCKET来接发消息:

上面这样用,我们就不用写什么代码什么的,如果自己写一个多播发送的消息,似乎更简单,生成的代码也小很多:像下面这个方法用来发送多播消息:


int sendtomt(){
int ret;
int s;
int i=1;
char buffer[2048] = {0};
struct sockaddr_in Multi_addr;//多播地址
struct sockaddr_in client_addr;
s=socket(AF_INET,SOCK_DGRAM,0);//建立数据报套接字
if(s<0){
perror("socket error");
return -1;
}
Multi_addr.sin_family=AF_INET;
Multi_addr.sin_port=htons(MCAST_PORT);//多播端口
Multi_addr.sin_addr.s_addr=inet_addr(MCAST_ADDR);//多播地址

//向多播组发送数据

int size=sendto(s,buff_define,strlen(buff_define),0,(struct sockaddr*)&Multi_addr,sizeof(Multi_addr));
if(size<0){
perror("sendto error");
}
sleep(1);
i++;
int len=sizeof(client_addr);
for(i = 0;i<10;i++){
memset(buffer,0,sizeof(buffer));
memset(&client_addr,0,sizeof(struct sockaddr));
size=recvfrom(s,buffer,2047,0,(struct sockaddr*)&client_addr,&len);
printf("=============:%s,%d=================i:%d======\nbuffer:%s\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port), i,buffer);
sleep(1);
}
close(s);
}
发送的内容,这个内容就要根据自己实际的东东改了:
char *buff_define = "<?xml version=\"1.0\" encoding=\"utf-8\"?> \
< Envelope \
xmlns:dn=\"http://www.onvif.org/ver10/network/wsdl\" \
xmlns=\"http://www.w3.org/2003/05/soap-envelope\"> \
< Header>\
< wsa:MessageID xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">uuid:4e7ca33c-1f95-4cba-a05a-
0079b3ba927f</wsa:MessageID>\
< wsa:To xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">urn:schemas-xmlsoap-
org:ws:2005:04:discovery</wsa:To>\
< wsa:Action
xmlns:wsa=\"http://schemas.xmlsoap.org/ws/2004/08/addressing\">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:
Action>\
< /Header> \
< Body> \
< Probe \
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \
xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" \
xmlns=\"http://schemas.xmlsoap.org/ws/2005/04/discovery\"> \
< Types>dn:NetworkVideoTransmitter</Types> \
< Scopes /> \
< /Probe> \
< /Body> \
< /Envelope>";
这个方法,麻烦的是,你还需要自己解收到的XML,但我们可以找一个轻量级的XML库来做,因为不需要改写XML,这个库能解XML的内容就可以了.

  评论这张
 
阅读(1413)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017