# 完整数据流程设计 ## 用户需求 1. **自动解析**:服务端在给定协议下自动解析数据到header和struct,Handler中直接使用 2. **自动编码**:服务端写数据时自动编码 ## 完整数据流程 ### 读数据流程(自动解析) ``` 1. 数据到达 Connection.Read() → []byte (原始字节) ↓ 2. 识别协议 根据配置或数据特征识别协议 → Protocol ↓ 3. 协议解码 Protocol.Decode(rawData) → FrameHeader + []byte (帧头 + 数据部分) ↓ 4. 识别编解码器 根据配置或路由配置识别编解码器 → Codec ↓ 5. 获取请求类型 从路由配置获取请求类型 → RequestType (reflect.Type) ↓ 6. 数据解码 Codec.Decode(bodyBytes, requestType) → Go Struct ↓ 7. 创建Request对象 Request.SetHeader(header) Request.SetData(struct) // 已解析的结构体 ↓ 8. 创建Context Context包含Request和Response ↓ 9. Handler执行 req.Data().(*MyStruct) // 直接使用解析后的结构体 ``` ### 写数据流程(自动编码) ``` 1. Handler调用 resp.Write(struct) // Go对象 ↓ 2. 编解码器编码 Codec.Encode(struct) → []byte (序列化后的数据) ↓ 3. 协议编码 Protocol.Encode(bodyBytes, header) → []byte (添加帧头) ↓ 4. 写入连接 Connection.Write(frameData) → 发送到客户端 ``` ## 关键实现点 ### 1. 服务器自动解析 在服务器接收到数据后,立即进行解析: ```go func (h *eventHandler) OnTraffic(c gnet.Conn) { // 1. 读取原始数据 rawData, _ := c.Peek(-1) // 2. 识别协议 protocol := h.identifyProtocol(rawData) // 3. 创建Request对象(初始状态) req := request.New(rawData, protocol) // 4. 创建Response对象 resp := response.New(connAdapter, protocol, h.codecRegistry, h.defaultCodec) // 5. 创建Context ctx := context.New(parentCtx, conn, req, resp) // 6. 路由匹配(会返回路由配置) route, handler := h.router.Match(rawData, ctx) if route == nil { return } // 7. 自动解析请求数据 if route.RequestType() != nil { h.parseRequest(req, rawData, route, protocol, h.codecRegistry) } // 8. 执行Handler(Handler中可以直接使用解析后的数据) handler(ctx) } ``` ### 2. 自动解析逻辑 ```go func (h *eventHandler) parseRequest(req request.Request, rawData []byte, route Route, protocol Protocol, codecRegistry CodecRegistry) { // 1. 协议解码(提取帧头和数据) header, bodyBytes, err := protocol.Decode(rawData) if err != nil { // 处理错误 return } req.SetHeader(header) req.SetDataBytes(bodyBytes) // 2. 数据解码(将字节解码为结构体) requestType := route.RequestType() if requestType != nil { // 创建结构体实例 body := reflect.New(requestType.Elem()).Interface() // 获取编解码器 codec := codecRegistry.Get(route.Codec()) // 或使用默认编解码器 if codec == nil { codec = codecRegistry.Default() } // 解码数据 if err := codec.Decode(bodyBytes, body); err != nil { // 处理错误 return } // 设置到Request req.SetData(body) } } ``` ### 3. 自动编码逻辑 ```go func (resp *responseImpl) Write(data interface{}) error { // 1. 获取编解码器 codec := resp.codecRegistry.Default() // 或从路由获取 // 2. 编解码器编码(Go对象 → 字节) bodyBytes, err := codec.Encode(data) if err != nil { return err } // 3. 协议编码(添加帧头) header := resp.Header() frameData, err := resp.protocol.Encode(bodyBytes, header) if err != nil { return err } // 4. 写入连接 return resp.conn.Write(frameData) } ``` ## Handler使用示例 ### 有帧头协议 ```go type LoginRequest struct { Username string `json:"username"` Password string `json:"password"` } type LoginResponse struct { Code int `json:"code"` Token string `json:"token"` } // 注册路由 router.RegisterString( "login", loginHandler, router.WithRequestType(&LoginRequest{}), ) // Handler实现 func loginHandler(ctx context.Context) error { req := ctx.Request() resp := ctx.Response() // 直接使用解析后的数据(无需手动解码) loginReq := req.Data().(*LoginRequest) username := loginReq.Username password := loginReq.Password // 读取协议帧头(如果有) header := req.Header() if header != nil { messageType := header.Get("message_type") sequence := header.Get("sequence") // 使用帧头信息 } // 处理业务逻辑 token := authenticate(username, password) // 设置响应帧头(如果有) respHeader := resp.Header() if respHeader != nil { respHeader.Set("message_type", 0x02) respHeader.Set("sequence", sequence) respHeader.Set("status", 0) } // 写入响应(自动编码) return resp.Write(LoginResponse{ Code: 200, Token: token, }) } ``` ### 无帧头协议 ```go type EchoRequest struct { Message string `json:"message"` } type EchoResponse struct { Message string `json:"message"` } // 注册路由 router.RegisterString( "echo", echoHandler, router.WithRequestType(&EchoRequest{}), ) // Handler实现 func echoHandler(ctx context.Context) error { req := ctx.Request() resp := ctx.Response() // 直接使用解析后的数据(无帧头协议,header为nil) echoReq := req.Data().(*EchoRequest) // 写入响应(自动编码,协议会自动添加\n等分隔符) return resp.Write(EchoResponse{ Message: echoReq.Message, }) } ``` ## 协议帧头处理 ### 有帧头协议(如nnet) ```go // nnet协议格式 [Magic(4 bytes)][Version(1 byte)][Length(4 bytes)][Data(N bytes)][Checksum(2 bytes)] // 协议解码 func (p *NNetProtocol) Decode(data []byte) (FrameHeader, []byte, error) { // 提取帧头 header := &NNetFrameHeader{ Magic: data[0:4], Version: data[4], Length: binary.BigEndian.Uint32(data[5:9]), Checksum: binary.BigEndian.Uint16(data[9+length:11+length]), } // 提取数据部分 bodyBytes := data[9:9+length] return header, bodyBytes, nil } // 协议编码 func (p *NNetProtocol) Encode(data []byte, header FrameHeader) ([]byte, error) { // 构建完整的协议帧 frame := make([]byte, 0, 11+len(data)) frame = append(frame, header.Magic...) frame = append(frame, header.Version) // ... 其他帧头字段 frame = append(frame, data...) frame = append(frame, header.Checksum...) return frame, nil } ``` ### 无帧头协议(如\n分割) ```go // 无帧头协议 func (p *NoHeaderProtocol) HasHeader() bool { return false } // 协议解码 func (p *NoHeaderProtocol) Decode(data []byte) (FrameHeader, []byte, error) { // 无帧头,直接返回数据(去除分隔符) data = bytes.TrimSuffix(data, []byte{'\n'}) return nil, data, nil // 返回nil header } // 协议编码 func (p *NoHeaderProtocol) Encode(data []byte, header FrameHeader) ([]byte, error) { // 无帧头,直接返回数据(添加分隔符) return append(data, '\n'), nil } ``` ## 路由配置 ### 支持指定请求类型 ```go // RouteOption 路由选项 type RouteOption func(*routeConfig) // WithRequestType 指定请求类型 func WithRequestType(typ interface{}) RouteOption { return func(cfg *routeConfig) { cfg.requestType = reflect.TypeOf(typ) } } // WithCodec 指定编解码器 func WithCodec(codecName string) RouteOption { return func(cfg *routeConfig) { cfg.codecName = codecName } } // 使用示例 router.RegisterString( "login", loginHandler, router.WithRequestType(&LoginRequest{}), router.WithCodec("json"), ) ``` ## 总结 ### ✅ 已实现 1. **Context职责分离**:Context只负责状态管理 2. **Request和Response对象**:负责数据读写 3. **自动编码**:Response.Write()自动编码 4. **接口定义**:Request、Response、Protocol接口已定义 ### 🚧 待实现 1. **自动解析**:服务器自动解析数据 2. **路由配置**:支持指定请求类型 3. **协议实现更新**:更新现有协议实现 4. **服务器代码更新**:更新服务器以使用新架构 ## 下一步 1. 实现自动解析逻辑 2. 更新路由接口,支持指定请求类型 3. 更新协议实现 4. 更新服务器代码 5. 编写测试用例