计算机网络中的设计模式
代理模式
代理模式可以在不改变客户端代码的情况下,通过代理对象来控制对实际对象的访问。
网络中最高频出现的设计模式之一,在传输层之上的应用层使用非常广泛。
- HTTP 代理
- DNS 代理
- 防火墙
伪代码
// 代理处理器伪代码实现
func proxyHandler(w http.ResponseWriter, r *http.Request) {
// 解析目标服务器 URL
target, err := url.Parse("https://dbwu.tech/")
...
// 将客户端的请求转发给目标服务器
proxyReq, err := http.NewRequest(r.Method, ...)
...
// 发送请求到目标服务器
client := &http.Client{}
resp, err := client.Do(proxyReq)
...
// 复制目标服务器的响应头
for key, values := range resp.Header {
for _, value := range values {
w.Header().Add(key, value)
}
}
// 设置响应状态码
w.WriteHeader(resp.StatusCode)
// 将目标服务器的响应内容复制到客户端响应
io.Copy(w, resp.Body)
}
func main() {
// 将代理处理器注册到根路径
http.HandleFunc("/", proxyHandler)
// 启动 HTTP 服务器
log.Fatal(http.ListenAndServe(":8080", nil))
}
装饰者模式
最经典的就是发送方从应用层到物理层的各类协议头部格式,层层包装,接收方从物理层到应用层,反过来,层层解包装。
伪代码
采用 Golang Functional Options 风格来实现。
package main
// 所有协议和装饰器都要实现这个 Packet 接口
type Packet interface {
GetContent() string
}
// PacketDecorator 装饰器
type PacketDecorator struct {
packet Packet
header string
}
func (d *PacketDecorator) GetContent() string {
return d.header + d.packet.GetContent()
}
// Option 设置 PacketDecorator 的属性
// Functional Options 模式
type Option func(*PacketDecorator)
// WithHeader 负责装饰,也就是各类协议的头部格式包装
func WithHeader(header string) Option {
return func(d *PacketDecorator) {
d.header = header
}
}
// ApplicationLayer 应用层
type ApplicationLayer struct {
data string
}
func (a *ApplicationLayer) GetContent() string {
return a.data
}
// TransportLayer 传输层装饰器
func TransportLayer(packet Packet, opts ...Option) Packet {
decorator := &PacketDecorator{packet: packet}
for _, opt := range opts {
opt(decorator)
}
return decorator
}
// NetworkLayer 网络层装饰器
func NetworkLayer(packet Packet, opts ...Option) Packet {
decorator := &PacketDecorator{packet: packet}
for _, opt := range opts {
opt(decorator)
}
return decorator
}
// DataLinkLayer 数据链路层装饰器
func DataLinkLayer(packet Packet, opts ...Option) Packet {
decorator := &PacketDecorator{packet: packet}
for _, opt := range opts {
opt(decorator)
}
return decorator
}
// PhysicalLayer 物理层装饰器
func PhysicalLayer(packet Packet, opts ...Option) Packet {
decorator := &PacketDecorator{packet: packet}
for _, opt := range opts {
opt(decorator)
}
return decorator
}
func main() {
// 创建应用层的数据
appData := &ApplicationLayer{data: "Hello, World!"}
// 逐层包装
transportPkt := TransportLayer(appData, WithHeader("[TCP Header]"))
networkPkt := NetworkLayer(transportPkt, WithHeader("[IP Header]"))
dataLinkPkt := DataLinkLayer(networkPkt, WithHeader("[Ethernet Header]"))
physicalPkt := PhysicalLayer(dataLinkPkt, WithHeader("[Physical Layer Header]"))
// 打印物理层数据
println(physicalPkt.GetContent())
}
运行上面的代码,输出如下:
[Physical Layer Header][Ethernet Header][IP Header][TCP Header]Hello, World!
状态模式
典型的例子就是 TCP 协议的实现 (一个复杂的状态机),使用状态模式可以简单地模拟 TCP 的状态机的工作机制,每个状态都可以表示为一个类,并且每个类都有相应的状态转换逻辑。
伪代码
一个完整的 TCP 状态机实现比较复杂,这里以 TCP 三次握手来演示状态模式。
为了节省篇幅,这里只演示 SYN_SENT
, SYN_RECEIVED
, Established
, Closed
4 种 TCP 连接状态。
package main
import (
"fmt"
)
// TCPState 定义状态行为接口
type TCPState interface {
Handle(context *TCPConnection)
String() string
}
// TCPConnection 是状态机上下文
// 包含当前状态机器所处状态
type TCPConnection struct {
state TCPState
}
func (c *TCPConnection) SetState(state TCPState) {
c.state = state
}
func (c *TCPConnection) Handle() {
c.state.Handle(c)
}
func (c *TCPConnection) String() string {
return c.state.String()
}
// 下面是具体的状态转移和变化过程
// SYN_SENT 代表 TCP SYN_SENT 状态
type SYN_SENT struct{}
// SYN_RECEIVED 代表 TCP SYN_RECEIVED 状态
type SYN_RECEIVED struct{}
// Established 代表 TCP ESTABLISHED 状态
type Established struct{}
// Closed 表示 TCP 连接已关闭状态
type Closed struct{}
func (s *Closed) Handle(context *TCPConnection) {
fmt.Println("Received SYN, transitioning to SYN_SENT")
context.SetState(&SYN_SENT{})
}
func (s *Closed) String() string {
return "CLOSED"
}
func (s *SYN_SENT) Handle(context *TCPConnection) {
fmt.Println("Received SYN-ACK, transitioning to SYN_RECEIVED")
context.SetState(&SYN_RECEIVED{})
}
func (s *SYN_SENT) String() string {
return "SYN_SENT"
}
func (s *SYN_RECEIVED) Handle(context *TCPConnection) {
fmt.Println("Received ACK, transitioning to ESTABLISHED")
context.SetState(&Established{})
}
func (s *SYN_RECEIVED) String() string {
return "SYN_RECEIVED"
}
func (s *Established) Handle(context *TCPConnection) {
fmt.Println("Connection is already ESTABLISHED")
}
func (s *Established) String() string {
return "ESTABLISHED"
}
func main() {
// 默认情况下,连接处于关闭状态
connection := &TCPConnection{state: &Closed{}}
fmt.Println("Current State:", connection)
fmt.Println("--------------------------")
// 客户端发起建立连接请求,状态转移到 SYN_SENT
connection.Handle()
fmt.Println("Current State:", connection)
fmt.Println("--------------------------")
// 服务端接收到建立连接请求,状态转移到 SYN_RECEIVED
connection.Handle()
fmt.Println("Current State:", connection)
fmt.Println("--------------------------")
// 客户端接收到服务端的 ACK,状态转移到 ESTABLISHED
connection.Handle()
fmt.Println("Current State:", connection)
fmt.Println("--------------------------")
connection.Handle()
}
运行上面的代码,输出如下:
Current State: CLOSED
--------------------------
Received SYN, transitioning to SYN_SENT
Current State: SYN_SENT
--------------------------
Received SYN-ACK, transitioning to SYN_RECEIVED
Current State: SYN_RECEIVED
--------------------------
Received ACK, transitioning to ESTABLISHED
Current State: ESTABLISHED
--------------------------
Connection is already ESTABLISHED
策略模式
策略模式可以将请求的处理逻辑封装到不同的策略类中,并在运行时选择合适的策略来处理请求,使具体的算法处理逻辑可以灵活地扩展和修改。
TCP 协议中的拥塞控制算法、路由选择算法等都可以使用策略模式来确定具体使用哪种算法。
伪代码
package main
import "fmt"
// CongestionControl 定义拥塞控制算法接口
type CongestionControl interface {
Execute()
}
// Reno 拥塞控制算法实现
type Reno struct{}
func (r *Reno) Execute() {
fmt.Println("Using Reno Algorithm")
}
// Cubic 拥塞控制算法实现
type Cubic struct{}
func (c *Cubic) Execute() {
fmt.Println("Using Cubic Algorithm")
}
// BBR 拥塞控制算法实现
type BBR struct{}
func (b *BBR) Execute() {
fmt.Println("Using BBR Algorithm")
}
// Connection 是连接,可以选择使用具体的算法
type Connection struct {
strategy CongestionControl
}
// SetStrategy 设置当前的算法
func (c *Connection) SetStrategy(strategy CongestionControl) {
c.strategy = strategy
}
// Handle 执行当前的拥塞控制算法
func (c *Connection) Handle() {
c.strategy.Execute()
}
func main() {
connection := &Connection{}
// 使用 Reno 拥塞控制算法
reno := &Reno{}
connection.SetStrategy(reno)
connection.Handle()
// 使用 Cubic 拥塞控制算法
cubic := &Cubic{}
connection.SetStrategy(cubic)
connection.Handle()
// 使用 BBR 拥塞控制算法
bbr := &BBR{}
connection.SetStrategy(bbr)
connection.Handle()
}
运行上面的代码,输出如下:
Using Reno Algorithm
Using Cubic Algorithm
Using BBR Algorithm