📹 第八章 ONVIF框架代码案例应用
📄 一句话概括

单播问「你」,组播问「关心这件事的各位」,广播问「全网段所有人」。 ONVIF 选组播的理由只有一个:广播出不了网段,而单播要先知道地址。

📝 本节和前面几节的关系

上一节讲完 WS-Discovery 的机制,这一节把三种寻址方式摆在一起比。 这是网络基础,但放在 ONVIF 上下文里比较才有意义—— 因为这里的选择直接决定了「能不能跨网段发现」。

一、三种寻址方式

方式 地址 一对几 跨网段
单播 对方 IP 一对一 能
组播 239.255.255.250 一对多,只给加入组的 要路由器支持
广播 255.255.255.255 一对全网段 不能

第四列是 ONVIF 选组播的全部理由: 广播出不了网段——一栋楼三层,每层一个 VLAN,广播就废了。 而组播在跨网段时依赖「组播路由」(IGMP + PIM), 这是企业网里常见的配置项—— 所以「发现不了设备」这个故障,很多时候不在设备上,在交换机的 IGMP 配置上。 第一列那个「单播能跨网段」也是有条件的:要能路由到对方,而「不知道地址」就无从谈起。

二、组播地址是规定好的

239.255.255.250 与端口 3702 是 WS-Discovery 定死的,不是 ONVIF 自己选的—— 所以理论上「任何支持 WS-Discovery 的设备」都在这个地址上喊话, 包括打印机、扫描仪、智能电视。

项 值 能不能改
组播地址 239.255.255.250 不能,规范定死
端口 3702 不能
本机绑定的地址 0.0.0.0(所有网卡) 能,但没必要

第三行有个实际问题:一台机器有两个网卡(有线 + 无线)时, 0.0.0.0 会让它从两个网卡都发一遍, 于是同一台设备可能被「发现两次」—— 所以客户端要按 EndpointReference(UUID)去重,不能按 IP 去重。 这个坑在笔记本上调试时特别常见: 插着网线又开着 WiFi,搜出来一堆重复设备,还以为设备有问题。

三、本机实测三种

这一节的值在于「真跑一遍」,因为三种方式在不同系统上表现差别很大:

方式 本机结果 说明
单播 通 回环上的单播,正常
组播 通 绑 3702 + join + 自发自收,都成功
广播 通 只能说「没被拦」,没有对象回

第二行那个「通」要解释清楚:我既发了 Probe、又绑了 3702 并加入了组播组, 所以收到的那条其实是自己发出去的——这证明「组播路径通」,不证明「设备会应答」。 两件事必须分开说,不然很容易把「能发包」当成「能发现设备」。 第三行那个「通」更弱:广播没有回执,「发出去了」只说明系统没拦, 所以「用广播搜索设备」在工程上从来不是可靠手段。

四、什么时候真要考虑组播

日常用不上,但两种场景必须考虑:

场景 为什么必须组播 注意什么
大规模部署 几百台设备,单播要逐个填 IP 组播路由要配
跨网段发现 广播出不去 交换机要开 IGMP snooping
实时流分发 一人推、多人看省带宽 这是 RTSP 的组播,不是发现

第一行是「发现」的用途,第三行是「取流」的用途——两者都叫组播,但是两件事: 发现是一次性的 UDP 报文,取流是持续的 RTP 流。 混起来讲是很多资料的毛病, 结果读者以为「组播发现」和「组播取流」是同一套配置—— 其实前者的地址是定死的,后者由 GetStreamUri 里的 RTP-Multicast 决定。 第二行那个 IGMP snooping 值得单独记一句: 不开它,组播会在交换机里泛洪成广播——表现是「一开组播,整个网段都卡」。

五、动手 Demo:单播、组播、广播,本机各通不通

Demo 三种都试一遍,成功失败都如实打出来。 重点是看「组播」那一行到底通不通——这台机器的结果不能代表所有机器,所以必须实测。

# ① 单播:往回环上某个端口发
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(b"x", ("127.0.0.1", 9)); s.close()

# ② 组播:绑 3702、join 239.255.255.250、自发自收
print(D.try_multicast())

# ③ 广播:开 SO_BROADCAST 再发
print(D.try_broadcast())

实跑输出:

--------------------------------------------------------------------
单播、组播、广播,本机各通不通
--------------------------------------------------------------------
**这三种地址不是「随便挑一个」,各有各的适用面**:

  方式         地址                  一对几                         要不要路由器配合
  -----------------------------------------------------------------------------------
  单播         对方 IP               一对一                         不要
  **组播**     `239.255.255.250`     **一对多,只发给加入组的**     **要**
  广播         `255.255.255.255`     一对全网段                     **不跨网段**

**ONVIF 选组播的理由在第三、四列**:
**广播出不了网段,而摄像机可能在任何网段**;
**单播要先知道地址,可「发现」这件事本身就是为了找地址**——
**只剩组播:不知道地址也能问到,且只吵到「关心这件事的机器」。**

**我把三种都在本机试了一遍,结果如下**:

  方式     结果       实测细节
  ---------------------------------------------------------------------------
  单播     **通**     能发(回环上的单播)
  组播     **通**     绑 3702 成功、join 成功、发出 630 字节,收到自己的回环
  广播     **通**     广播发出去了(没有对象回,所以只能说「没被拦」)

**第二行那句「收到自己的回环」要解释一下,不然会误解**:
**我既发了 Probe 又绑了 3702 并加入了组播组**,
**所以收到的那条其实是自己发出去的**——
**这证明「组播路径是通的」,不证明「设备会应答」。**
**两件事必须分开说**,不然很容易把「能发包」当成「能发现设备」。

**第三行也有个坑**:广播「发出去了」只说明系统没拦,
**不代表有人收到**——**广播没有回执**,
**所以「广播搜索设备」在工程上从来不是可靠手段。**

第二段那行是最有信息量的:绑 3702 成功、join 成功、发出 630 字节,收到自己的回环。 三件事都成功,但结论要保守:「收到的是自己发的」这一点必须强调, 否则读者会以为「组播发现已经通了」。 第三段的输出是「广播发出去了(没有对象回)」,这句措辞是刻意的: 广播没有回执,所以只能说「没被拦」。 如果哪天要在这台机器上做真的组播测试, 得有两台机器、同一个网段、都没开防火墙拦 UDP 3702——这三条缺一条,测试结果就没意义。 最后那句「工程上从来不用广播搜索设备」是有历史原因的:早期的设备搜索工具确实用广播, 后来因为跨不了网段、又容易被防火墙拦,才统一到 WS-Discovery。

30 秒实验

  1. 把 try_multicast() 的 seconds 改成 3,看结果会不会变。
  2. 在 try_broadcast() 里加一个 socket 收包,看能不能收到自己发的广播。
  3. 查一下你所在网段的交换机有没有开 IGMP snooping,这决定了组播能不能跨网段。

常见误区

  1. 以为「组播能发出去」就等于「能发现设备」。 收到自己发的包只证明路径通, 不证明有设备在听。
  2. 用广播搜索设备。 广播出不了网段,而且没有回执,工程上从来不是可靠手段。
  3. 把「组播发现」和「组播取流」当成一件事。 前者的地址是定死的 239.255.255.250, 后者由 RTP-Multicast 决定。
自测三问(点开对答案) 1. ONVIF 为什么选组播而不是广播? —— **因为广播出不了网段**,而摄像机可能在任何网段。组播靠组播路由能跨,广播不能。 2. 本机测出「组播通」,能得出什么结论? —— **只能得出「组播路径通」**——因为收到的是自己发的包。**不能推出「设备会应答」。** 3. 一台机器有线和无线同时开,为什么设备会被发现两次? —— **因为组播绑的是 `0.0.0.0`,两个网卡各发一遍。**客户端要按 UUID 去重,不能按 IP。

下一节把发现和信息获取串起来:从一句「谁在」到拿到厂家型号。

相关笔记