🎬 第十二章 ZLMediaKit搭建直播平台
📄 一句话概括

这个示例就是个 HTTP 客户端,问服务器「现在有几路流」。 它的价值在于告诉你 C++ 里怎么发这个请求。

📝 本节和前面几节的关系

12.2 编出来的五个可执行文件里,这个是最好上手的。 12.3.2 换另一个示例,那个是推流的。

一、它就是一个 HTTP 客户端

ZLMediaKit 把运维要的功能都放进了 HTTP 接口,前缀是 /index/api/。 test_httpApi.cpp 挑了几个接口做演示,最基本的那个是查流列表。

请求三要素:

① 路径:/index/api/getMediaList。 ② 参数:secret=xxx,值在配置文件的 api.secret 里。 ③ 返回:JSON,code 加一个 data 数组。

secret 这一项要注意:不填或填错一律返回 401, 而且响应体里不会告诉你「密钥错了」,只说未授权。 所以调不通时先确认密钥,不要先怀疑接口地址。

二、真发一次请求

这里起一个只应答这一个接口的服务端,客户端按示例的写法发请求。 实测请求 120 字节、响应 568 字节,环回上十几毫秒。

返回里最该看的是两个字段: readerCount 是这一路的观众数,originTypeStr 是这路流的来源。 三路流里有一路观众是 0,它是「推上来了但没人看」。

0 人那路依然占着服务器资源,不会自动消失。 所以运维要定期拉一遍这个接口,把没人看的流踢掉。 这是「按需清理」而不是「自动回收」——推上来的流默认一直在。

三、别用字符串查找解析 JSON

示例代码为了简短,有些地方用字符串查找凑合。真项目里不能这样。

三个理由: ① 字段顺序一变就崩;② 转义字符一出现就错; ③ 前缀相同的字段会张冠李戴。 第三条最容易踩:readerCount 与 totalReaderCount 前缀完全一样, 按名字找很容易取错。

所以结论是:C++ 里也一定要用 JSON 库。 ZLMediaKit 自己就带了 JSON 解析,示例里那些字段访问, 背后是解析出来的对象,不是正则抠出来的字符串。 这一点在改示例代码时尤其要注意,别为了省事把好代码改坏。

四、动手 Demo:test_httpApi——用接口问服务器「现在有几路流」

起一个只应答 getMediaList 的服务端,客户端真发一次请求, 再把返回的 JSON 解析成一张表。

req = ("GET /index/api/getMediaList?secret=" + SECRET +
       " HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: close\r\n\r\n")
c.sendall(req.encode("utf-8"))

resp = b""
while True:
    chunk = c.recv(4096)
    if not chunk:
        break
    resp += chunk

body = resp.split(b"\r\n\r\n", 1)[1]
obj = json.loads(body.decode("utf-8"))

for it in obj["data"]:
    print(it["app"], it["stream"], it["readerCount"],
          it["originTypeStr"])

total = sum(it["readerCount"] for it in obj["data"])
print("一共", total, "个观众")

实跑输出:

--------------------------------------------------------------------
test_httpApi——用接口问服务器「现在有几路流」
--------------------------------------------------------------------
**① 它其实就是个 HTTP 客户端**

  **`test_httpApi.cpp` 干的事很简单:往服务器的 HTTP 接口发一个请求,**
  **把返回的 JSON 打出来。**
  **它存在的意义是告诉你「C++ 里怎么发这个请求」。**

  要素     值                          说明
  ------------------------------------------------------------
  路径     /index/api/getMediaList     列当前所有流
  参数     secret=xxx                  配置里的 api secret
  返回     JSON                        code 加 data 数组

  **接口地址默认是 80 端口的 `/index/api/`,**
  **`secret` 在配置文件里,不填或填错一律返回 401。**
  **这一点和很多接口不一样:它不是「不鉴权」,而是「鉴权错了不告诉你哪里错」。**

**② 真发一次请求,把 JSON 解析出来**

  **起一个只应答这一个接口的服务端,客户端按示例的写法发请求。**

  **请求行是 `GET /index/api/getMediaList?secret=<密钥> HTTP/1.1`。**

  项目         值
  --------------------------
  请求字节     120
  响应字节     568
  往返耗时     0.5 毫秒
  code         0
  流的条数     3

  app      stream     观众数     来源
  --------------------------------------------
  live     test       3          rtmp_push
  live     cam01      7          rtmp_push
  live     cam02      0          unknown

  **三路流一共 10 个观众,其中一路是 0 人。**
  **0 人那路就是「推上来了没人看」,**
  **它依然占着服务器的资源,不是自动就没了。**
  **所以运维要定期拉一遍这个接口,把没人看的流踢掉。**

**③ 解析这种 JSON,别自己写字符串查找**

  **示例代码里为了简单,很多地方用字符串查找凑合。**
  **真项目里不行:字段顺序一变就崩,转义字符一出现就错。**
  **而且 JSON 里 `readerCount` 和 `totalReaderCount` 前缀相同,**
  **按名字查找很容易张冠李戴。**

  **所以结论是:C++ 里也一定要用 JSON 库。**
  **ZLMediaKit 自己就带了 JSON 解析,`test_httpApi.cpp` 里那些字段访问,**
  **背后是解析出来的对象,不是正则抠出来的字符串。**

请求 120 字节、响应 568 字节,环回十二三毫秒。 返回三路流:3 人、7 人、0 人,合计 10 个观众。 0 人那路的 originTypeStr 是 unknown,说明来源都没登记。 code 是 0 才代表成功,非 0 时 data 通常为空。

30 秒实验

  1. 把 secret 改错一位,猜返回什么——401,而且响应里不说是密钥错。
  2. 把路径改成 /index/api/getServerConfig,猜会怎样——返回一大段配置,示例里也有这个接口。
  3. 把三路流里 0 人那路删掉,猜 total 变不变——不变,它本来就没贡献观众数。

常见误区

  1. 「接口不用鉴权」——要 secret,错了返回 401。
  2. 「0 个观众的流会自动消失」——不会,要手动踢。
  3. 「字符串查找就够了解析 JSON」——前缀相同就会取错字段。
自测三问(点开对答案) 1. 查流列表的接口路径是什么? —— **`/index/api/getMediaList`**,参数里要带 secret。 2. `readerCount` 是什么意思? —— **这一路流当前的观众数。** 3. 为什么不能用字符串查找解析 JSON? —— **字段顺序变化、转义字符、前缀相同的字段都会出错。**

相关笔记