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.

288 lines
6.0 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.

# 编解码器和协议集成说明
## 功能概述
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`
- ✅ 自动编解码器匹配
- ✅ 协议层编码(可选)
- ✅ 自定义编解码器
- ✅ 向后兼容(支持直接写入字节或字符串)
这大大简化了服务端写数据到客户端的操作,开发者无需手动处理编码逻辑。