You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

328 lines
7.4 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 架构重新设计 - 问题解答
## 问题1Context不应该包含数据写入读取功能
**您的思考:** ✅ **完全正确**
Context应该专注于状态管理和流程控制数据读写应该交给Request、Response或Connection完成。
**新的设计:**
```go
// Context只负责状态管理
type Context interface {
context.Context
Request() Request // 获取Request对象
Response() Response // 获取Response对象
Connection() Connection // 获取Connection对象
Set(key string, value interface{})
Get(key string) interface{}
}
// Request负责数据读取
type Request interface {
Raw() []byte // 原始数据
Data() []byte // 协议解码后的数据
Decode(v interface{}) error // 解码为Go对象
Header() FrameHeader // 协议帧头
}
// Response负责数据写入
type Response interface {
Write(data interface{}) error // 写入数据(自动编码)
WriteBytes(data []byte) error // 写入原始字节
SetHeader(header FrameHeader) // 设置协议帧头
Send() error // 发送响应
}
```
## 问题2协议帧 = 帧头(协议处理)+ 帧数据Codec处理
**您的理解:** ✅ **完全正确**
协议帧的结构:
```
[帧头] + [数据]
↓ ↓
Protocol Codec
```
**设计实现:**
```go
// Protocol处理帧头
type Protocol interface {
HasHeader() bool // 是否有帧头
Encode(data []byte, header FrameHeader) ([]byte, error) // 添加帧头
Decode(data []byte) (FrameHeader, []byte, error) // 提取帧头和数据
}
// Codec处理数据序列化
type Codec interface {
Encode(v interface{}) ([]byte, error) // 序列化
Decode(data []byte, v interface{}) error // 反序列化
}
```
**数据流程:**
读数据:
```
原始字节 → Protocol.Decode() → 帧头 + 数据 → Codec.Decode() → Go对象
```
写数据:
```
Go对象 → Codec.Encode() → 数据 → Protocol.Encode() → 帧头 + 数据 → 原始字节
```
## 问题3写数据时希望可以连同帧头一起写入
**您的需求:** ✅ **已支持**
**实现方式:**
### 方式1自动处理推荐
```go
func handler(ctx context.Context) error {
resp := ctx.Response()
// 设置协议帧头
header := resp.Header()
if header != nil {
header.Set("message_type", 0x01)
header.Set("sequence", 123)
}
// 写入数据(自动添加帧头)
return resp.Write(MyResponse{Code: 200})
}
```
### 方式2手动构建
```go
func handler(ctx context.Context) error {
resp := ctx.Response()
// 手动构建帧头
header := NewFrameHeader()
header.Set("message_type", 0x01)
resp.SetHeader(header)
// 写入数据
return resp.Write(MyResponse{Code: 200})
}
```
### 方式3直接写入原始字节
```go
func handler(ctx context.Context) error {
resp := ctx.Response()
// 手动构建完整的协议帧
frameHeader := []byte{0x01, 0x02, 0x03} // 自定义帧头
data := []byte("your data")
frame := append(frameHeader, data...)
// 直接写入(绕过自动编码)
return resp.WriteBytes(frame)
}
```
## 问题4无帧头协议支持如\n分割
**您的需求:** ✅ **已支持**
**实现方式:**
### 无帧头协议实现
```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
}
```
### 使用示例
```go
func handler(ctx context.Context) error {
req := ctx.Request()
resp := ctx.Response()
// 无帧头协议,直接读取数据
rawData := req.Data() // 已经是去除分隔符的数据
// 处理数据
result := processData(rawData)
// 写入响应(协议会自动添加\n
return resp.WriteString(result)
}
```
## 问题5综合考虑路由、协议选择、协议版本等功能
**您的需求:** ✅ **已考虑**
### 路由集成
路由可以在不同层次进行匹配:
1. **协议层匹配**:根据协议帧头匹配
```go
// 根据帧头的message_type字段匹配
router.RegisterFrameHeader("message_type", "==", 0x01, handler)
```
2. **数据层匹配**:根据解码后的数据匹配
```go
// 根据JSON数据的path字段匹配
router.RegisterFrameData("path", "==", "/api/user", handler)
```
3. **原始数据匹配**:根据原始字节匹配(无帧头协议)
```go
// 根据原始字符串匹配
router.RegisterString("get_user\n", handler)
```
### 协议选择
```go
// 配置协议
cfg := &Config{
Protocol: ProtocolConfig{
Name: "nnet", // 协议名称
Version: "1.0", // 协议版本
HasHeader: true, // 是否有帧头
},
}
// 服务器自动选择协议
server := NewServer(cfg)
```
### 协议版本管理
```go
// 协议管理器支持多版本
protocolManager.Register(nnetProtocolV1) // 版本1.0
protocolManager.Register(nnetProtocolV2) // 版本2.0
// 根据数据自动识别版本
protocol, version := protocolManager.Identify(data)
```
## 问题6API设计要精简、现代化
**您的需求:** ✅ **已实现**
### API特点
1. **简洁直观**
```go
// 读取数据
req.Decode(&data)
// 写入数据
resp.Write(data)
```
2. **类型安全**
```go
// 使用接口和泛型保证类型安全
req.Decode(&MyRequest{})
resp.Write(MyResponse{})
```
3. **链式调用**
```go
// 支持流畅的API
resp.Header().Set("type", 0x01).Write(data)
```
4. **自动处理**
```go
// 自动编码/解码
req.Decode(&data) // 自动进行protocol decode + codec decode
resp.Write(data) // 自动进行codec encode + protocol encode
```
## 完整的数据流程
### 读数据流程
```
1. Connection.Read() → []byte (原始字节)
2. Protocol.Decode() → FrameHeader + []byte (帧头 + 数据)
3. Request.Data() → []byte (数据部分)
4. Request.Decode() → interface{} (Go对象经过codec decode)
5. 路由匹配(可以根据帧头或数据匹配)
6. 处理器使用解码后的数据
```
### 写数据流程
```
1. Response.Write(interface{}) → Go对象
2. Codec.Encode() → []byte (序列化后的数据)
3. Protocol.Encode() → []byte (添加帧头)
4. Connection.Write() → 发送到客户端
```
## 实现状态
### ✅ 已完成
- [x] 接口定义Context、Request、Response、Protocol、FrameHeader
- [x] 设计文档
- [x] API设计文档
### 🚧 进行中
- [ ] Request和Response的具体实现
- [ ] 协议实现的更新
- [ ] 服务器代码的更新
### 📋 待实现
- [ ] 测试用例
- [ ] 性能优化
- [ ] 文档更新
## 总结
新的架构设计完全满足您的所有需求:
1. ✅ Context不包含数据读写功能
2. ✅ 协议帧 = 帧头Protocol+ 数据Codec
3. ✅ 支持连同帧头一起写入
4. ✅ 支持无帧头协议
5. ✅ 综合考虑路由、协议选择、协议版本
6. ✅ API设计精简、现代化
接下来可以开始实现具体的功能。