Skip to content

Commit 5ff88da

Browse files
committed
doc: update lite docker
1 parent a5d43c4 commit 5ff88da

11 files changed

Lines changed: 1835 additions & 32 deletions

File tree

.vitepress/config.mts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ const commonThemeConfig = (locales: '' | 'zh' | 'en' = '', translation = transla
8383
{ text: translation.sidebar.task, link: locales + '/develop/task' },
8484
{ text: translation.sidebar.relay, link: locales + '/develop/relay' },
8585
{ text: translation.sidebar.http, link: locales + '/develop/http' },
86-
{ text: translation.sidebar.alias, link: locales + '/develop/alias' }
86+
{ text: translation.sidebar.alias, link: locales + '/develop/alias' },
87+
{ text: translation.sidebar.reuse, link: locales + '/arch/reuse' },
88+
{ text: translation.sidebar.readerDesignPhilosophy, link: locales + '/arch/reader_design_philosophy' }
8789
]
8890
}
8991
],

.vitepress/i18n/en.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ export default {
168168
log: 'Logging',
169169
task: 'Task System',
170170
relay: 'Relay System',
171-
http: 'HTTP'
171+
http: 'HTTP',
172+
arch: 'Architecture',
173+
reuse: 'Reuse',
174+
readerDesignPhilosophy: 'Reader Design Philosophy'
172175
},
173176
themeConfig: {
174177
siteTitle: 'Monibuca v5',

.vitepress/i18n/zh.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ export default {
168168
log: '日志系统',
169169
task: '任务系统',
170170
relay: '中继系统',
171-
http: 'HTTP'
171+
http: 'HTTP',
172+
arch: '架构设计',
173+
reuse: '对象复用',
174+
readerDesignPhilosophy: 'Reader接口设计哲学'
172175
},
173176
themeConfig: {
174177
siteTitle: 'Monibuca v5',
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# 贯彻 Go 语言 Reader 接口设计哲学:以 Monibuca 中的流媒体处理为例
2+
3+
## 引言
4+
5+
Go 语言以其简洁、高效和并发安全的设计哲学而闻名,其中 io.Reader 接口是这一哲学的典型体现。在实际业务开发中,如何正确运用 io.Reader 接口的设计思想,对于构建高质量、可维护的系统至关重要。本文将以 Monibuca 流媒体服务器中的 RTP 数据处理为例,深入探讨如何在实际业务中贯彻 Go 语言的 Reader 接口设计哲学,包括同步编程模式、单一职责原则、关注点分离以及组合复用等核心概念。
6+
7+
## 什么是 Go 语言的 Reader 接口设计哲学?
8+
9+
Go 语言的 io.Reader 接口设计哲学主要体现在以下几个方面:
10+
11+
1. **简单性**:io.Reader 接口只定义了一个方法 `Read(p []byte) (n int, err error)`,这种极简设计使得任何实现了该方法的类型都可以被视为一个 Reader。
12+
13+
2. **组合性**:通过组合不同的 Reader,可以构建出功能强大的数据处理管道。
14+
15+
3. **单一职责**:每个 Reader 只负责一个特定的任务,符合单一职责原则。
16+
17+
4. **关注点分离**:不同的 Reader 负责处理不同的数据格式或协议,实现了关注点的分离。
18+
19+
## Monibuca 中的 Reader 设计实践
20+
21+
在 Monibuca 流媒体服务器中,我们设计了一系列的 Reader 来处理不同层次的数据:
22+
23+
1. **SinglePortReader**:处理单端口多路复用的数据流
24+
2. **RTPTCPReader****RTPUDPReader**:分别处理 TCP 和 UDP 协议的 RTP 数据包
25+
3. **RTPPayloadReader**:从 RTP 包中提取有效载荷
26+
4. **AnnexBReader**:处理 H.264/H.265 的 Annex B 格式数据
27+
28+
> 备注:在处理 PS流时从RTPPayloadReader还要经过 PS包解析、PES包解析才进入 AnnexBReader
29+
30+
### 同步编程模式
31+
32+
Go 的 io.Reader 接口天然支持同步编程模式。在 Monibuca 中,我们通过同步方式逐层处理数据:
33+
34+
```go
35+
// 从 RTP 包中读取数据
36+
func (r *RTPPayloadReader) Read(buf []byte) (n int, err error) {
37+
// 如果缓冲区中有数据,先读取缓冲区中的数据
38+
if r.buffer.Length > 0 {
39+
n, _ = r.buffer.Read(buf)
40+
return n, nil
41+
}
42+
43+
// 读取新的 RTP 包
44+
err = r.IRTPReader.Read(&r.Packet)
45+
// ... 处理数据
46+
}
47+
```
48+
49+
这种同步模式使得代码逻辑清晰,易于理解和调试。
50+
51+
### 单一职责原则
52+
53+
每个 Reader 都有明确的职责:
54+
55+
- **RTPTCPReader**:只负责从 TCP 流中解析 RTP 包
56+
- **RTPUDPReader**:只负责从 UDP 数据包中解析 RTP 包
57+
- **RTPPayloadReader**:只负责从 RTP 包中提取有效载荷
58+
- **AnnexBReader**:只负责解析 Annex B 格式的数据
59+
60+
这种设计使得每个组件都非常专注,易于测试和维护。
61+
62+
### 关注点分离
63+
64+
通过将不同层次的处理逻辑分离到不同的 Reader 中,我们实现了关注点的分离:
65+
66+
```go
67+
// 创建 RTP 读取器的示例
68+
switch mode {
69+
case StreamModeUDP:
70+
rtpReader = NewRTPPayloadReader(NewRTPUDPReader(conn))
71+
case StreamModeTCPActive, StreamModeTCPPassive:
72+
rtpReader = NewRTPPayloadReader(NewRTPTCPReader(conn))
73+
}
74+
```
75+
76+
这种分离使得我们可以独立地修改和优化每一层的处理逻辑,而不会影响其他层。
77+
78+
### 组合复用
79+
80+
Go 语言的 Reader 设计哲学鼓励通过组合来复用代码。在 Monibuca 中,我们通过组合不同的 Reader 来构建完整的数据处理管道:
81+
82+
```go
83+
// RTPPayloadReader 组合了 IRTPReader
84+
type RTPPayloadReader struct {
85+
IRTPReader // 组合接口
86+
// ... 其他字段
87+
}
88+
89+
// AnnexBReader 可以与 RTPPayloadReader 组合使用
90+
annexBReader := &AnnexBReader{}
91+
rtpReader := NewRTPPayloadReader(NewRTPUDPReader(conn))
92+
```
93+
94+
## 数据处理流程时序图
95+
96+
为了更直观地理解这些 Reader 是如何协同工作的,我们来看一个时序图:
97+
98+
```mermaid
99+
sequenceDiagram
100+
participant C as 客户端
101+
participant S as 服务器
102+
participant SPR as SinglePortReader
103+
participant RTCP as RTPTCPReader
104+
participant RTPU as RTPUDPReader
105+
participant RTPP as RTPPayloadReader
106+
participant AR as AnnexBReader
107+
108+
C->>S: 发送 RTP 数据包
109+
S->>SPR: 接收数据
110+
SPR->>RTCP: TCP 模式数据解析
111+
SPR->>RTPU: UDP 模式数据解析
112+
RTCP->>RTPP: 提取 RTP 包有效载荷
113+
RTPU->>RTPP: 提取 RTP 包有效载荷
114+
RTPP->>AR: 解析 Annex B 格式数据
115+
AR-->>S: 返回解析后的 NALU 数据
116+
```
117+
118+
## 实际应用中的设计模式
119+
120+
在 Monibuca 中,我们采用了多种设计模式来更好地贯彻 Reader 接口的设计哲学:
121+
122+
### 1. 装饰器模式
123+
124+
RTPPayloadReader 装饰了 IRTPReader,在读取 RTP 包的基础上增加了有效载荷提取功能。
125+
126+
### 2. 适配器模式
127+
128+
SinglePortReader 适配了多路复用的数据流,将其转换为标准的 io.Reader 接口。
129+
130+
### 3. 工厂模式
131+
132+
通过 `NewRTPTCPReader``NewRTPUDPReader` 等工厂函数来创建不同类型的 Reader。
133+
134+
## 性能优化与最佳实践
135+
136+
在实际应用中,我们还需要考虑性能优化:
137+
138+
1. **内存复用**:通过 `util.Buffer``util.Memory` 来减少内存分配
139+
2. **缓冲机制**:在 RTPPayloadReader 中使用缓冲区来处理不完整的数据包
140+
3. **错误处理**:通过 `errors.Join` 来合并多个错误信息
141+
142+
## 结论
143+
144+
通过在 Monibuca 流媒体服务器中的实践,我们可以看到 Go 语言的 Reader 接口设计哲学在实际业务中的强大威力。通过遵循同步编程模式、单一职责原则、关注点分离和组合复用等设计理念,我们能够构建出高内聚、低耦合、易于维护和扩展的系统。
145+
146+
这种设计哲学不仅适用于流媒体处理,也适用于任何需要处理数据流的场景。掌握并正确运用这些设计原则,将有助于我们编写出更加优雅和高效的 Go 代码。

0 commit comments

Comments
 (0)