我正在尝试使用一些Java代码来发现ONVIF设备。具体来说,我正在尝试获取它们的设备服务地址(我相信这只是他们的IP地址?),如ONVIF Core Spec所述(在第4. 3节中)“成功的发现提供设备服务地址。一旦客户端获得设备服务地址,它就可以通过设备服务接收详细的设备信息..."。最终获得网络上ONVIF设备的详细信息是我的目标。一般来说,我也在寻找一些与使用ONVIF规范相关的指导。
我对Web服务世界(以及一般的网络)还是个新手,所以请原谅我说了一些愚蠢的话,但是,我自己已经为此付出了很多努力:我读了很多关于ONVIF Core Spec、ONVIF Application Programmer's Guide和WS-Discovery Specification的书,如果可以的话,我想总结一下我所知道的,这样你就可以告诉我,我的思路是否正确:
1.“Web服务”是一种标准技术的名称,它使用独立于平台和语言的Web服务标准,如IP网络上的XML、SOAP和WSDL。基本思想是我们希望能够从任何编程语言调用有效的方法/函数(服务)。
- web服务通常托管在服务器上;但在ONVIF用例中,网络服务提供商是ONVIF设备(例如,IP摄像头)。因此,为了从任何语言与设备交互,我们使用网络服务操作/调用,因为网络服务调用可以用任何语言实现。
- XML是数据描述语法(使用它是因为它与语言无关;任何语言都可以解析它)。SOAP是用于来回获取SOAP注入的XML文档的通信协议(基本上,进行我们的方法调用)。WSDL用于描述服务(它是Web服务接口的基于XML的描述)。我已经下载了用于设备管理here的WSDL,并通过WSDL编译器
wsimport
(由JDK提供)从WSDL生成Java类以在代码中使用。但是我知道调用这些方法将在设备发现之后进行,对吗? - ONVIF设备是根据WS-Discovery规范发现的。您发送
Probe
消息,匹配探测器约束的设备将发回ProbeMatch
消息,如第13页和第14页in ONVIF Application Programmers Guide所述
这就是我开始感到困惑的地方。我究竟如何在Java中发送这个消息?ONVIF应用程序编程人员指南在第15页提供了一些伪代码,但我不知道如何实现它。该指南中的4.3.1节是我特别坚持的地方。我知道“作用域”和“类型”只是可以嵌入到探测器中的约束。但它们不是必需的(根据X1 E6 F1 X的第5页)。由于我想发现所有设备,我想我不需要任何约束来启动,对吗?
因此,该指南还在第110页提供了一个用于发现的SOAP消息示例,删除了其中的类型声明(因为我不需要那个约束),我知道要发送的SOAP消息将是(我相信?):
<?xml version="1.0" encoding="UTF-8"?>
<e:Envelope xmlns:e="http://www.w3.org/2003/05/soap-envelope"
xmlns:w="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:d="http://schemas.xmlsoap.org/ws/2005/04/discovery"
xmlns:dn="http://www.onvif.org/ver10/network/wsdl">
<e:Header>
<w:MessageID>uuid:84ede3de-7dec-11d0-c360-f01234567890</w:MessageID>
<w:To e:mustUnderstand="true">urn:schemas-xmlsoap-org:ws:2005:04:discovery</w:To>
<w:Action
a:mustUnderstand="true">http://schemas.xmlsoap.org/ws/2005/04/discovery/Pr
obe</w:Action>
</e:Header>
<e:Body>
<d:Probe>
</d:Probe>
</e:Body>
</e:Envelope>
我也知道WS-Discovery技术使用了地址239.255.255.259和UDP端口3702......但这就是我所得到的结果。我如何在Java中将SOAP消息发送到该地址和端口?我如何读取响应(我 * 认为 * 我将以注入SOAP的XML文档的形式返回ProbeMatch消息,因此我需要解析该XML以获得XAddrs
,但不确定)。我是否需要以某种方式将该SOAP消息的UDP广播发送到该地址?
TL;DR:我认为要执行ONVIF设备发现,我需要将上面的SOAP消息发送到UDP端口3702上的地址239.255.255.259。我不知道如何在Java中执行此操作,只是在寻找一些指导;我甚至不确定我是否走在了设备发现的正确道路上。
3条答案
按热度按时间5uzkadbs1#
通过大量的试验和错误,我找到了解决我的问题的另一种方法。mpromonet可能是大多数情况下要走的路,我只是想避免使用像Apache这样的大依赖性。我还认为这应该是可以做到的,只是一些简单的UDP消息。
这个解决方案也是基于SO用户托马斯的有用代码here。我主要是通过删除线程简化了他的代码,并添加了一些注解。同样,他的解决方案可能比我的更好(性能更高);但是,我的可能更容易理解一个初学者(像我)。
下面是代码:
使用此功能的一些注意事项:
1.要使用此解决方案,您需要知道要查看的“网络接口”。在我的代码中,这是192.168.0.50。这是我要查找的摄像头所在的网络。要查找此接口,请在cmd提示符下运行
arp -a
命令(不确定如何在Mac或Linux上做到这一点),然后定位你的摄像头的IP。它福尔斯的接口就是你想要用来做那个“192. 168. 0. 50”的接口。在我有限的理解中,这些接口基本上将你的网络分段,所以你需要选择一个合适的接口来查找设备。我认为(?)托马斯的代码通过查找所有这些网络接口来避免这个问题。这在his code的第81-100行中完成。1.当你发送探测器的时候,你必须给予它一个唯一的UUID,这是我做这件事时犯的一个错误;我在探测器(
WS_DISCOVERY_PROBE_MESSAGE
)中测试了一个硬编码的UUID,它可以一次性发现设备;但是在那之后,如果你用相同的UUID发送一个探测器,设备似乎根本不会回复。你也不会得到错误响应,这就是为什么我很坚韧找到答案。这就好像设备保存了一些内部日志,记录了所有接收到的探测器的UUID;如果你发送一个带有旧UUID的探头,它会拒绝它。或者至少,我正在测试的兼容ONVIF的摄像机(AXIS M3045-V)就是这种情况。我不确定ONVIF规范是否 * 要求 * 这种行为,但至少在AXIS M3045-V中很明显。1.注意:SOAP通常依赖于HTTP进行传输;但这里我们在UDP上使用它。
我希望这能帮助任何想做类似事情的人。如果有什么我能帮上忙的,请告诉我;在这一点上,我已经阅读了大量的文档,所以我可能可以帮上忙!
yc0p9oo02#
使用CXF WSDiscoveryClient可以探测ONVIF设备。
默认情况下,WSDiscoveryClient使用WS-discovery 1.1,ONVIF使用WS-discovery 1.0,因此您需要启用WS-discovery 1.0。
一个简短的实现可以是:
bbuxkriu3#
我已经修改了一个库来与ONVIF摄像头接口。它使用WS-Discovery进行发现。它目前在获取友好名称方面做得不好。我正在研究如何在不进行身份验证的情况下获取该名称。它是一个Kotlin库,有一个JVM目标,所以我相信您可以从Java使用它。
https://github.com/sproctor/ONVIF-Camera-Kotlin/