开发一台 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 秒实验
- 给迷你设备加一个 WS-Discovery 的组播响应,看能不能被
GetServices之外的方式发现。 - 把鉴权从「有没有 Security 元素」改成「校验密码」,数要加多少行。
- 把
OPS表里的操作数从 30 改成 5,看响应函数的删除是不是也能一对一删。
常见误区
- 以为「能调通」就等于「符合 ONVIF」。 一致性测试考的是细节完备性(鉴权摘要、错误码分类、 命名空间),不是「常用路径能不能走」。
- 以为设备端要自己手写所有序列化。 现实里都用 gSOAP 生成,人只填业务函数。
- 以为 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:逐个功能拆开, 从概念定义和缩写表开始,然后是发现、管理、媒体、云台、事件、分析、存储。
- ☐ (本节完,下一节 07.02.01 概念定义)