|
|
# 架构重新设计 - 基于最佳实践
|
|
|
|
|
|
## 设计原则
|
|
|
|
|
|
1. **关注点分离(Separation of Concerns)**
|
|
|
- Context:状态管理和流程控制
|
|
|
- Request:数据读取和解码
|
|
|
- Response:数据编码和写入
|
|
|
- Connection:底层网络读写
|
|
|
- Protocol:协议帧头处理
|
|
|
- Codec:数据序列化
|
|
|
|
|
|
2. **现代化API设计**
|
|
|
- 精简、直观、类型安全
|
|
|
- 参考Gin、Fiber等框架的设计理念
|
|
|
- 支持链式调用和流畅的API
|
|
|
|
|
|
3. **灵活性**
|
|
|
- 支持有帧头协议(如nnet)和无帧头协议(如\n分割)
|
|
|
- 支持自定义协议和编解码器
|
|
|
- 支持协议版本管理
|
|
|
|
|
|
## 核心架构
|
|
|
|
|
|
### 1. Context(上下文)
|
|
|
|
|
|
**职责:** 状态管理和流程控制,不直接处理数据读写
|
|
|
|
|
|
```go
|
|
|
type Context interface {
|
|
|
context.Context
|
|
|
|
|
|
// 获取Request和Response对象
|
|
|
Request() Request
|
|
|
Response() Response
|
|
|
Connection() Connection
|
|
|
|
|
|
// 状态管理
|
|
|
Set(key string, value interface{})
|
|
|
Get(key string) interface{}
|
|
|
MustGet(key string) interface{}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 2. Request(请求)
|
|
|
|
|
|
**职责:** 数据读取、协议解码、编解码器解码
|
|
|
|
|
|
```go
|
|
|
type Request interface {
|
|
|
// 原始数据(未解码的字节)
|
|
|
Raw() []byte
|
|
|
|
|
|
// 协议解码后的数据(去除帧头后的字节)
|
|
|
Data() []byte
|
|
|
|
|
|
// 解码为Go对象(经过protocol decode + codec decode)
|
|
|
Decode(v interface{}) error
|
|
|
DecodeWithCodec(v interface{}, codecName string) error
|
|
|
|
|
|
// 协议帧头(如果有)
|
|
|
Header() FrameHeader
|
|
|
|
|
|
// 协议信息
|
|
|
Protocol() Protocol
|
|
|
ProtocolVersion() string
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 3. Response(响应)
|
|
|
|
|
|
**职责:** 数据编码、协议编码、数据写入
|
|
|
|
|
|
```go
|
|
|
type Response interface {
|
|
|
// 写入数据(自动编码)
|
|
|
Write(data interface{}) error
|
|
|
WriteWithCodec(data interface{}, codecName string) error
|
|
|
|
|
|
// 写入原始字节(绕过编码)
|
|
|
WriteBytes(data []byte) error
|
|
|
WriteString(s string) error
|
|
|
|
|
|
// 协议帧头操作(如果有)
|
|
|
SetHeader(header FrameHeader) error
|
|
|
Header() FrameHeader
|
|
|
|
|
|
// 发送响应(如果使用缓冲模式)
|
|
|
Send() error
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 4. FrameHeader(协议帧头)
|
|
|
|
|
|
**职责:** 协议帧头的数据结构
|
|
|
|
|
|
```go
|
|
|
type FrameHeader interface {
|
|
|
// 获取帧头字段
|
|
|
Get(key string) interface{}
|
|
|
Set(key string, value interface{})
|
|
|
|
|
|
// 编码为字节
|
|
|
Encode() ([]byte, error)
|
|
|
|
|
|
// 从字节解码
|
|
|
Decode(data []byte) error
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 5. Protocol(协议)
|
|
|
|
|
|
**职责:** 协议帧头的编码和解码
|
|
|
|
|
|
```go
|
|
|
type Protocol interface {
|
|
|
Name() string
|
|
|
Version() string
|
|
|
|
|
|
// 编码(添加帧头)
|
|
|
Encode(data []byte, header FrameHeader) ([]byte, error)
|
|
|
|
|
|
// 解码(提取帧头和数据)
|
|
|
Decode(data []byte) (FrameHeader, []byte, error)
|
|
|
|
|
|
// 是否有帧头(无帧头协议返回false)
|
|
|
HasHeader() bool
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 数据流程
|
|
|
|
|
|
### 读数据流程
|
|
|
|
|
|
```
|
|
|
1. Connection.Read() → []byte (原始字节)
|
|
|
↓
|
|
|
2. Protocol.Decode() → FrameHeader + []byte (帧头 + 数据)
|
|
|
↓
|
|
|
3. Codec.Decode() → interface{} (Go对象)
|
|
|
↓
|
|
|
4. Request.Decode() → 提供给处理器使用
|
|
|
```
|
|
|
|
|
|
### 写数据流程
|
|
|
|
|
|
```
|
|
|
1. Response.Write(interface{}) → Go对象
|
|
|
↓
|
|
|
2. Codec.Encode() → []byte (序列化后的数据)
|
|
|
↓
|
|
|
3. Protocol.Encode() → []byte (添加帧头)
|
|
|
↓
|
|
|
4. Connection.Write() → 发送到客户端
|
|
|
```
|
|
|
|
|
|
## 无帧头协议支持
|
|
|
|
|
|
对于无帧头协议(如\n分割),Protocol实现:
|
|
|
|
|
|
```go
|
|
|
type NoHeaderProtocol struct{}
|
|
|
|
|
|
func (p *NoHeaderProtocol) HasHeader() bool {
|
|
|
return false // 无帧头
|
|
|
}
|
|
|
|
|
|
func (p *NoHeaderProtocol) Encode(data []byte, header FrameHeader) ([]byte, error) {
|
|
|
// 无帧头协议,直接返回数据,可能添加分隔符
|
|
|
return append(data, '\n'), nil
|
|
|
}
|
|
|
|
|
|
func (p *NoHeaderProtocol) Decode(data []byte) (FrameHeader, []byte, error) {
|
|
|
// 无帧头协议,直接返回数据(去除分隔符)
|
|
|
data = bytes.TrimSuffix(data, []byte{'\n'})
|
|
|
return nil, data, nil // 返回nil header
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## API设计示例
|
|
|
|
|
|
### 基本使用
|
|
|
|
|
|
```go
|
|
|
// 处理器
|
|
|
func handler(ctx context.Context) error {
|
|
|
req := ctx.Request()
|
|
|
resp := ctx.Response()
|
|
|
|
|
|
// 读取请求(自动解码)
|
|
|
var requestData MyRequest
|
|
|
if err := req.Decode(&requestData); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
// 处理业务逻辑
|
|
|
responseData := MyResponse{
|
|
|
Code: 200,
|
|
|
Data: "success",
|
|
|
}
|
|
|
|
|
|
// 写入响应(自动编码)
|
|
|
return resp.Write(responseData)
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 自定义协议帧头
|
|
|
|
|
|
```go
|
|
|
func handler(ctx context.Context) error {
|
|
|
req := ctx.Request()
|
|
|
resp := ctx.Response()
|
|
|
|
|
|
// 读取协议帧头
|
|
|
header := req.Header()
|
|
|
if header != nil {
|
|
|
messageType := header.Get("message_type")
|
|
|
// 使用帧头信息
|
|
|
}
|
|
|
|
|
|
// 读取数据
|
|
|
var data MyData
|
|
|
req.Decode(&data)
|
|
|
|
|
|
// 设置响应帧头
|
|
|
respHeader := NewFrameHeader()
|
|
|
respHeader.Set("message_type", 0x01)
|
|
|
resp.SetHeader(respHeader)
|
|
|
|
|
|
// 写入响应
|
|
|
return resp.Write(MyResponse{Code: 200})
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 无帧头协议
|
|
|
|
|
|
```go
|
|
|
func handler(ctx context.Context) error {
|
|
|
req := ctx.Request()
|
|
|
resp := ctx.Response()
|
|
|
|
|
|
// 无帧头协议,直接读取原始数据
|
|
|
rawData := req.Data() // 或 req.Raw()
|
|
|
|
|
|
// 处理数据
|
|
|
result := processData(rawData)
|
|
|
|
|
|
// 写入响应(协议会自动添加\n)
|
|
|
return resp.WriteString(result)
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### 指定编解码器
|
|
|
|
|
|
```go
|
|
|
func handler(ctx context.Context) error {
|
|
|
req := ctx.Request()
|
|
|
resp := ctx.Response()
|
|
|
|
|
|
// 使用指定的编解码器解码
|
|
|
var data MyData
|
|
|
req.DecodeWithCodec(&data, "msgpack")
|
|
|
|
|
|
// 使用指定的编解码器编码
|
|
|
return resp.WriteWithCodec(MyResponse{Code: 200}, "msgpack")
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 配置设计
|
|
|
|
|
|
```go
|
|
|
type Config struct {
|
|
|
// 协议配置
|
|
|
Protocol struct {
|
|
|
Name string // 协议名称
|
|
|
Version string // 协议版本
|
|
|
HasHeader bool // 是否有帧头
|
|
|
}
|
|
|
|
|
|
// 编解码器配置
|
|
|
Codec struct {
|
|
|
Default string // 默认编解码器
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
## 路由集成
|
|
|
|
|
|
路由匹配可以在不同层次进行:
|
|
|
|
|
|
1. **协议层匹配**:根据协议帧头匹配(如果有)
|
|
|
2. **数据层匹配**:根据解码后的数据匹配
|
|
|
3. **原始数据匹配**:根据原始字节匹配(无帧头协议)
|
|
|
|
|
|
## 实现计划
|
|
|
|
|
|
### 第一阶段:核心接口定义
|
|
|
1. 定义Context、Request、Response接口
|
|
|
2. 定义FrameHeader接口
|
|
|
3. 更新Protocol接口
|
|
|
|
|
|
### 第二阶段:实现Request和Response
|
|
|
1. 实现Request的读取和解码功能
|
|
|
2. 实现Response的编码和写入功能
|
|
|
3. 集成协议和编解码器
|
|
|
|
|
|
### 第三阶段:更新Context
|
|
|
1. 移除Context中的数据读写方法
|
|
|
2. 添加Request和Response对象
|
|
|
3. 更新所有使用Context的地方
|
|
|
|
|
|
### 第四阶段:更新服务器
|
|
|
1. 更新服务器中的数据流程
|
|
|
2. 实现协议解码逻辑
|
|
|
3. 实现协议编码逻辑
|
|
|
|
|
|
### 第五阶段:测试和优化
|
|
|
1. 编写测试用例
|
|
|
2. 性能优化
|
|
|
3. 文档更新
|
|
|
|
|
|
## 优势
|
|
|
|
|
|
1. **清晰的职责分离**:每个组件职责明确
|
|
|
2. **灵活的扩展性**:支持各种协议和编解码器
|
|
|
3. **现代化的API**:简洁、直观、类型安全
|
|
|
4. **向后兼容**:可以逐步迁移现有代码
|
|
|
5. **最佳实践**:参考了主流框架的设计理念
|
|
|
|