# 编解码器和协议集成说明 ## 功能概述 nnet库现在支持: 1. ✅ **任意类型数据写入**:通过`ctx.WriteAny(data)`写入任意Go类型 2. ✅ **自动编解码器匹配**:根据配置自动选择编解码器(JSON、Binary、Protobuf、MessagePack) 3. ✅ **协议层编码**:可选地支持协议层编码(如nnet协议的Magic、长度、校验和) 4. ✅ **自定义编解码器**:支持注册和使用自定义编解码器 ## 服务端写数据到客户端 ### 方式一:写入字节数据(基础方式) ```go func handler(ctx ctxpkg.Context) error { data := []byte("Hello, World!") return ctx.Write(data) } ``` ### 方式二:写入字符串 ```go func handler(ctx ctxpkg.Context) error { return ctx.WriteString("Hello, World!") } ``` ### 方式三:写入任意类型(自动编码)⭐ 推荐 ```go type Response struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data"` } func handler(ctx ctxpkg.Context) error { resp := Response{ Code: 200, Message: "success", Data: map[string]interface{}{"user_id": 123}, } // 自动使用配置的默认编解码器(默认是binary) return ctx.WriteAny(resp) } ``` ### 方式四:指定编解码器 ```go func handler(ctx ctxpkg.Context) error { resp := Response{Code: 200, Message: "success"} // 使用JSON编解码器 ctx.WriteAnyWithCodec(resp, "json") // 使用MessagePack编解码器 ctx.WriteAnyWithCodec(resp, "msgpack") // 使用Protobuf编解码器 ctx.WriteAnyWithCodec(resp, "protobuf") return nil } ``` ## 配置编解码器 ### 基本配置 ```go cfg := &nnet.Config{ Addr: "tcp://:8080", Codec: &nnet.CodecConfig{ DefaultCodec: "binary", // 默认编解码器(库默认) EnableProtocolEncode: false, // 是否启用协议层编码 }, } ``` ### 启用协议层编码 ```go cfg := &nnet.Config{ Addr: "tcp://:8080", Codec: &nnet.CodecConfig{ DefaultCodec: "json", EnableProtocolEncode: true, // 启用协议层编码 }, } ``` 启用协议层编码后,数据会经过: 1. **编解码器编码**:将Go对象编码为字节数组(如JSON) 2. **协议编码**:将字节数组包装为协议格式(如nnet协议的Magic、长度、校验和) ## 支持的编解码器 ### 1. JSON(可选,默认为 binary) ```go // 自动使用JSON编码 ctx.WriteAny(data) ``` ### 2. Binary ```go // 使用二进制编码 ctx.WriteAnyWithCodec(data, "binary") ``` ### 3. Protobuf ```go // 使用Protobuf编码(需要实现proto.Message接口) ctx.WriteAnyWithCodec(data, "protobuf") ``` ### 4. MessagePack ```go // 使用MessagePack编码 ctx.WriteAnyWithCodec(data, "msgpack") ``` ## 协议层编码 ### nnet协议格式 如果启用了协议层编码,数据会按照nnet协议格式编码: ``` [Magic(4 bytes)][Version(1 byte)][Length(4 bytes)][Data(N bytes)][Checksum(2 bytes)] ``` - Magic: "NNET" (4字节) - Version: 协议版本(1字节) - Length: 数据长度(4字节,大端序) - Data: 实际数据(N字节) - Checksum: 校验和(2字节,大端序) ### 使用示例 ```go cfg := &nnet.Config{ Addr: "tcp://:8080", Codec: &nnet.CodecConfig{ DefaultCodec: "json", EnableProtocolEncode: true, // 启用nnet协议编码 }, } server, _ := nnet.NewServer(cfg) // 在处理器中 func handler(ctx ctxpkg.Context) error { resp := Response{Code: 200, Message: "success"} // 数据会先JSON编码,然后使用nnet协议编码 return ctx.WriteAny(resp) } ``` ## 自定义编解码器 ### 实现编解码器接口 ```go type MyCodec struct{} func (c *MyCodec) Encode(v interface{}) ([]byte, error) { // 实现编码逻辑 return []byte("encoded"), nil } func (c *MyCodec) Decode(data []byte, v interface{}) error { // 实现解码逻辑 return nil } func (c *MyCodec) Name() string { return "mycodec" } ``` ### 注册自定义编解码器 ```go server, _ := nnet.NewServer(cfg) // 注册自定义编解码器 myCodec := &MyCodec{} server.CodecRegistry().Register("mycodec", myCodec) // 使用自定义编解码器 ctx.WriteAnyWithCodec(data, "mycodec") ``` ## 协议管理器 ### 注册协议 ```go server, _ := nnet.NewServer(cfg) // 获取协议管理器 protocolManager := server.ProtocolManager() // 注册nnet协议 nnetProtocol := internalprotocol.NewNNetProtocol("1.0") protocolManager.Register(nnetProtocol) ``` ### 获取协议 ```go // 获取协议 protocol, err := protocolManager.Get("nnet", "1.0") if err != nil { // 处理错误 } ``` ## 完整示例 ```go package main import ( "github.com/noahlann/nnet" ctxpkg "github.com/noahlann/nnet/pkg/context" ) type Response struct { Code int `json:"code"` Data interface{} `json:"data"` } func main() { // 配置服务器 cfg := &nnet.Config{ Addr: "tcp://:8080", Codec: &nnet.CodecConfig{ DefaultCodec: "json", EnableProtocolEncode: false, }, } // 创建服务器 server, err := nnet.NewServer(cfg) if err != nil { panic(err) } // 注册路由 server.Router().RegisterString("hello", func(ctx ctxpkg.Context) error { // 方式1:写入字符串 ctx.WriteString("Hello, World!") // 方式2:写入结构体(自动JSON编码) resp := Response{Code: 200, Data: "success"} ctx.WriteAny(resp) // 方式3:使用指定的编解码器 ctx.WriteAnyWithCodec(resp, "msgpack") return nil }) // 启动服务器 server.Start() } ``` ## 总结 nnet库现在完全支持: - ✅ 任意类型数据写入(`WriteAny`) - ✅ 自动编解码器匹配 - ✅ 协议层编码(可选) - ✅ 自定义编解码器 - ✅ 向后兼容(支持直接写入字节或字符串) 这大大简化了服务端写数据到客户端的操作,开发者无需手动处理编码逻辑。