📹 第七章 ONVIF协议原理解析
📄 一句话概括

开发一台 ONVIF 设备是七步:收 POST、解信封、按 action 分发、填响应、加鉴权、回发现、 过测试。 30 个操作就对应 30 个响应函数,这是硬性一对一——所以现实里没人从零写,都用 gSOAP 生成。

📝 本节和前面几节的关系

前六节都是「客户端视角」:怎么问设备。这一节翻过来,讲设备端要做什么。 这一节也是第八章的反面:第八章写客户端,这里说的是被调的那一端。

一、七步流程

步 做什么 产出物 最容易卡住的地方
1 起一个 HTTP 服务端 能收 POST 的 socket HTTP 头要解析对
2 解 SOAP 信封 一个 XML 解析器 命名空间
3 按 action 分发 一张 if 表 1.1 和 1.2 取值位置不同
4 填响应值 各操作的 Response 字段顺序和命名空间
5 加鉴权 校验 Security 头 摘要算法和时钟
6 回 WS-Discovery 组播响应 组播在容器里常被禁
7 过一致性测试 Test Tool 报告 细节一堆

第 5 步是唯一「错了也不会立刻发现」的一步:鉴权校验失败时,设备必须回 Fault 而不是断连, 很多固件直接断开,客户端只看到「连接被重置」,能查一整天。 第 6 步是「最不像代码」的一步:组播在某些网络环境里被禁(云主机、容器、企业网), 设备自己的日志里看不到任何异常——客户端就是发现不了它。

二、量化:一个能跑的最小实现有多大

本机这个迷你设备就是「最小可用」的样本,数一下它的规模:

指标 数值
文件 _onvifsim.py(单文件)
总行数 620 行
非空非注释 515 行
字节数 25496 字节
响应函数 30 个

30 个响应函数对应 30 个操作,一对一,省不掉。 这是 ONVIF 设备端工作量的下限:你支持几个操作,就得写几个响应函数(或者说, 就得填几个模板)。 真实设备要实现的比这多得多:device_service 一个 WSDL 里就有几十个操作, 全部实现是几百个函数、几万行代码。 所以现实里没人从零写——都用 gSOAP 生成框架(第六章那两步工具)。 生成了框架之后,你要做的只是「填业务函数」,这才是「开发一台 ONVIF 设备」的真实工作量。

三、这台迷你设备过不了测试

项 迷你设备 规范要求
鉴权 只判有没有 Security 元素 要验摘要和时钟偏差
WS-Discovery 没实现 Profile S 强制要求
错误码 统一 Sender 要按情况分 Sender/Receiver
命名空间 只声明了用到的 要符合规范里那张表

这四行是本节最该记住的部分:「能调通」和「过认证」差的不是代码量,是细节的完备性。 而细节正是 ONVIF 一致性测试要考的。 所以你会看到一种现象: 某设备「ONVIF 能用」但过不了认证——因为它实现了「常用路径」,没实现「全部约束」。 第四行那个「命名空间表」是最枯燥的一项:规范里逐条列出了每个元素该在哪个命名空间下, 错一个就过不了。 这也是为什么用 gSOAP 生成比手写强——它按 WSDL 生成的代码,命名空间天生是对的。

四、国标和 ONVIF 的分岔

ONVIF 是国际联盟的标准,GB/T 28181 是中国的国标。 两者解决同一类问题,但协议完全不同。

项 ONVIF GB/T 28181
信令 SOAP over HTTP SIP + XML
发现 WS-Discovery(组播) SIP REGISTER 到服务器
流 RTSP/RTP RTP over UDP/TCP(不一定要 RTSP)
目录 设备自己有一个地址 统一由 SIP 服务器编目

第三行的差别最实际:GB/T 28181 的流是「服务器指挥谁发给谁」,不一定有 RTSP 那套握手。 所以「会 ONVIF」不等于「会国标」——第九章会专门讲国标,这里只标出分岔口。 第四行是架构差异:ONVIF 是「客户端直接找设备」,国标是「一切经过中心服务器」。 这也决定了两者的适用场景不同(局域网 vs 城域级联网)。

五、动手 Demo:开发一台 ONVIF 设备,要写多少东西

本机没有摄像头固件、没有交叉编译链,流程只能照规范列。 但「要写多少东西」这件事可以量——用本机的迷你设备当样本,数它的规模。 所以这一节的 Demo 是「量自己的代码」,不是「跑设备」。

here = os.path.dirname(os.path.abspath(__file__))
path = os.path.join(here, "_onvifsim.py")
src = open(path, encoding="utf-8").read()
lines = src.split("\n")
code_lines = [x for x in lines
                if x.strip() and not x.strip().startswith("#")]

print(len(lines), len(code_lines), len(src.encode()))   # 620 515 25496
print(len(S.OPS))                                       # 30

实跑输出:

--------------------------------------------------------------------
开发一台 ONVIF 设备,要写多少东西
--------------------------------------------------------------------
**书里这一节讲的是「开发 IPC 的流程」。**  本机没有摄像头固件、没有交叉编译链,
**流程只能照规范列**。
  但**「要写多少东西」这件事可以量**——  用本机的迷你设备当样本,数它的规模。

**七步流程(设备端视角):**

  步    做什么                    产出物                  最容易卡住的地方
  --------------------------------------------------------------------------------------
  1     起一个 HTTP 服务端        能收 POST 的 socket     **HTTP 头要解析对**
  2     解 SOAP 信封              一个 XML 解析器         **命名空间**
  3     按 action 分发            一张 if 表              **1.1 和 1.2 取值位置不同**
  4     填响应值                  各操作的 Response       **字段顺序和命名空间**
  5     加鉴权                    校验 Security 头        **摘要算法和时钟**
  6     回 WS-Discovery           组播响应                **组播在容器里常被禁**
  7     过一致性测试              ONVIF Test Tool 报告    **细节一堆**

  **第 5 步是唯一「错了但不会立刻发现」的一步**:
  **鉴权校验失败时,设备必须回 Fault 而不是断连**,
  **很多固件直接断开,客户端只看到「连接被重置」,查一天。**

**量化:本机这个迷你设备有多大**

  **文件**:`_onvifsim.py`
  **总行数 631 行,其中非空非注释 523 行,25973 字节。**

  **这 523 行里干了什么:**

  部分                              大约占多少行      对应流程的哪一步
  ------------------------------------------------------------------------------
  信封与 Fault 模板                 约 12 行          第 2 步
  各操作的响应函数                  30 个             第 3、4 步
  HTTP 解析与分发                   约 90 行          第 1、3 步
  鉴权开关(只判有没有 Security)   约 6 行           第 5 步(**简化版**)

  **第二行那个「30 个」是一对一的**:  **30 个操作就对应 30 个响应函数**,
  **这是硬性的一对一,省不掉。**
  **真实设备要实现的比这多得多**:  **ONVIF 的 device_service 一个 WSDL 里就有几十个操作**,
  **全部实现是几百个函数、几万行代码。**
  **所以现实里没人从零写**——**都用 gSOAP 生成框架**(第六章)。

**这台迷你设备能过一致性测试吗?不能。**

  项                  迷你设备                  规范要求
  --------------------------------------------------------------------------------
  鉴权                只判有没有 Security 元素  **要验摘要和时钟偏差**
  WS-Discovery        **没实现**                Profile S 强制要求
  错误码              统一 `Sender`             要按情况分 `Sender`/`Receiver`
  命名空间            只声明了用到的            要符合规范里那张表

  **这张表是本节的诚实边界**:  **它够用来演示「报文长什么样、怎么调」,  但不够用来过认证。**
  **两者差的不是代码量,是「细节的完备性」**——  **而细节正是 ONVIF 一致性测试要考的。**

620 行里 515 行是「非空非注释」,占了 83%。 这个比例偏高,因为里面大量是 XML 字符串的续行——它们既不是空行也不是注释,但信息密度很低。 所以「行数」这个指标在 XML 密集的代码里会虚高。 30 个响应函数正好等于 30 个操作,这不是巧合,是 OPS 表的设计:一个操作挂一个工厂函数。 真实实现里也是一样的一对一,只不过每个函数要写几十行参数处理,不是一行 return。 「能过一致性测试吗」那张表的四行,每一行我都能对着代码指给你看: 鉴权只看 u"Security" not in body,WS-Discovery 根本没写,错误码全是 Sender。 这四行不是猜的,是读代码读出来的。

30 秒实验

  1. 给迷你设备加一个 WS-Discovery 的组播响应,看能不能被 GetServices 之外的方式发现。
  2. 把鉴权从「有没有 Security 元素」改成「校验密码」,数要加多少行。
  3. 把 OPS 表里的操作数从 30 改成 5,看响应函数的删除是不是也能一对一删。

常见误区

  1. 以为「能调通」就等于「符合 ONVIF」。 一致性测试考的是细节完备性(鉴权摘要、错误码分类、 命名空间),不是「常用路径能不能走」。
  2. 以为设备端要自己手写所有序列化。 现实里都用 gSOAP 生成,人只填业务函数。
  3. 以为 ONVIF 和 GB/T 28181 是同一套。 信令一个是 SOAP,一个是 SIP, 流的组织方式也不同——会一个不等于会另一个。
自测三问(点开对答案) 1. 开发一台 ONVIF 设备的七步是什么? —— **收 POST、解信封、按 action 分发、填响应、加鉴权、回 WS-Discovery、过一致性测试。** 2. 为什么「30 个操作对应 30 个响应函数」这件事重要? —— 因为它是**工作量的下限**:**支持几个操作就得写几个响应函数**, **这也是为什么没人从零写、都用 gSOAP 生成。** 3. ONVIF 和 GB/T 28181 最根本的架构差别是什么? —— **ONVIF 是客户端直接找设备,国标是一切经过 SIP 中心服务器。** **所以一个适合局域网,一个适合城域联网。**

07.01 这七节把 ONVIF 的「是什么」讲完了。下一节开始 07.02:逐个功能拆开, 从概念定义和缩写表开始,然后是发现、管理、媒体、云台、事件、分析、存储。

相关笔记