golang轻量级TCP服务器框架插件库easytcp的使用
golang轻量级TCP服务器框架插件库easytcp的使用
EasyTCP简介
EasyTCP是一个基于Go标准net
包实现的轻量级TCP服务器框架,具有以下特性:
- 非侵入式设计
- 支持路由处理器的管道式中间件
- 可自定义消息打包器、编解码器和日志器
- 提供便捷函数处理请求数据和发送响应
- 支持常用钩子函数
安装
使用以下命令安装EasyTCP:
$ go get -u github.com/DarthPestilane/easytcp
注意:EasyTCP使用Go Modules管理依赖。
快速开始
基础示例
package main
import (
"fmt"
"github.com/DarthPestilane/easytcp"
)
func main() {
// 创建带选项的服务器
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.NewDefaultPacker(), // 使用默认打包器
Codec: nil, // 不使用编解码器
})
// 注册路由,使用消息ID
// DefaultPacker将ID视为int类型
s.AddRoute(1001, func(c easytcp.Context) {
// 获取请求
req := c.Request()
// 处理逻辑...
fmt.Printf("[server] request received | id: %d; size: %d; data: %s\n", req.ID(), len(req.Data()), req.Data())
// 设置响应
c.SetResponseMessage(easytcp.NewMessage(1002, []byte("copy that")))
})
// 设置自定义日志器(可选)
easytcp.SetLogger(lg)
// 添加全局中间件(可选)
s.Use(recoverMiddleware)
// 设置钩子函数(可选)
s.OnSessionCreate = func(session easytcp.Session) {...}
s.OnSessionClose = func(session easytcp.Session) {...}
// 设置未找到路由处理器(可选)
s.NotFoundHandler(handler)
// 监听并服务
if err := s.Run(":5896"); err != nil && err != server.ErrServerStopped {
fmt.Println("serve error: ", err.Error())
}
}
使用编解码器的示例
// 创建带编解码器的服务器
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.NewDefaultPacker(), // 使用默认打包器
Codec: &easytcp.JsonCodec{}, // 使用JsonCodec
})
// 注册路由
s.AddRoute(1001, func(c easytcp.Context) {
// 解码请求数据并绑定到reqData
var reqData map[string]interface{}
if err := c.Bind(&reqData); err != nil {
// 处理错误
}
// 处理逻辑...
respId := 1002
respData := map[string]interface{}{
"success": true,
"feeling": "Great!",
}
// 编码响应数据并设置到上下文
if err := c.SetResponse(respId, respData); err != nil {
// 处理错误
}
})
架构设计
接受连接:
+------------+ +-------------------+ +----------------+
| | | | | |
| | | | | |
| tcp server |--->| accept connection |--->| create session |
| | | | | |
| | | | | |
+------------+ +-------------------+ +----------------+
会话中:
+------------------+ +-----------------------+ +----------------------------------+
| read connection |--->| unpack packet payload |--->| |
+------------------+ +-----------------------+ | |
| router (middlewares and handler) |
+------------------+ +-----------------------+ | |
| write connection |<---| pack packet payload |<---| |
+------------------+ +-----------------------+ +----------------------------------+
路由处理器中:
+----------------------------+ +------------+
| codec decode request data |--->| |
+----------------------------+ | |
| user logic |
+----------------------------+ | |
| codec encode response data |<---| |
+----------------------------+ +------------+
核心概念
路由
EasyTCP通过消息ID区分不同消息,消息会根据其ID通过中间件路由到对应的处理器。
请求流程:
+----------+ +--------------+ +--------------+ +---------+
| request |--->| |--->| |--->| |
+----------+ | | | | | |
| middleware 1 | | middleware 2 | | handler |
+----------+ | | | | | |
| response |<---| |<---| |<---| |
+----------+ +--------------+ +--------------+ +---------+
注册路由
s.AddRoute(reqID, func(c easytcp.Context) {
// 获取请求
req := c.Request()
// 处理逻辑...
fmt.Printf("[server] request received | id: %d; size: %d; data: %s\n", req.ID(), len(req.Data()), req.Data())
// 设置响应
c.SetResponseMessage(easytcp.NewMessage(respID, []byte("copy that")))
})
使用中间件
// 注册全局中间件(优先级高于路由级中间件)
s.Use(recoverMiddleware, logMiddleware, ...)
// 为单个路由注册中间件
s.AddRoute(reqID, handler, middleware1, middleware2)
// 中间件示例
var exampleMiddleware easytcp.MiddlewareFunc = func(next easytcp.HandlerFunc) easytcp.HandlerFunc {
return func(c easytcp.Context) {
// 前置处理...
next(c)
// 后置处理...
}
}
打包器(Packer)
打包器负责打包和解包消息负载。可以在创建服务器时设置自定义打包器。
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: new(MyPacker), // 可选,默认为DefaultPacker
})
自定义打包器示例
// CustomPacker 实现Packer接口,格式为 size(2)id(2)data(n)
type CustomPacker struct{}
func (p *CustomPacker) bytesOrder() binary.ByteOrder {
return binary.BigEndian
}
func (p *CustomPacker) Pack(msg *easytcp.Message) ([]byte, error) {
size := len(msg.Data()) // 仅数据部分大小
buffer := make([]byte, 2+2+size)
p.bytesOrder().PutUint16(buffer[:2], uint16(size))
p.bytesOrder().PutUint16(buffer[2:4], msg.ID().(uint16))
copy(buffer[4:], msg.Data())
return buffer, nil
}
func (p *CustomPacker) Unpack(reader io.Reader) (*easytcp.Message, error) {
headerBuffer := make([]byte, 2+2)
if _, err := io.ReadFull(reader, headerBuffer); err != nil {
return nil, fmt.Errorf("read size and id err: %s", err)
}
size := p.bytesOrder().Uint16(headerBuffer[:2])
id := p.bytesOrder().Uint16(headerBuffer[2:])
data := make([]byte, size)
if _, err := io.ReadFull(reader, data); err != nil {
return nil, fmt.Errorf("read data err: %s", err)
}
// 由于msg.ID是uint16类型,添加路由时也需使用uint16
msg := easytcp.NewMessage(id, data)
msg.Set("theWholeLength", 2+2+size) // 可设置自定义KV数据
return msg, nil
}
编解码器(Codec)
编解码器负责编码和解码消息数据。Codec是可选的,如果不设置,EasyTCP不会对消息数据进行编解码。
s := easytcp.NewServer(&easytcp.ServerOption{
Codec: &easytcp.JsonCodec{}, // 可选,JsonCodec是内置编解码器
})
使用编解码器的路由处理器示例:
s.AddRoute(reqID, func(c easytcp.Context) {
var reqData map[string]interface{}
if err := c.Bind(&reqData); err != nil { // 解码消息数据并绑定到reqData
// 处理错误...
}
req := c.Request()
fmt.Printf("[server] request received | id: %d; size: %d; data-decoded: %+v\n", req.ID(), len(req.Data()), reqData())
respData := map[string]string{"key": "value"}
if err := c.SetResponse(respID, respData); err != nil {
// 处理错误...
}
})
内置编解码器
-
JsonCodec:使用
encoding/json
作为默认实现,可通过构建标签切换为jsoniter:go build -tags=jsoniter .
-
ProtobufCodec:使用
google.golang.org/protobuf
实现 -
MsgpackCodec:使用
github.com/vmihailenco/msgpack
实现
完整示例
以下是一个完整的EasyTCP服务器示例,包含中间件和自定义处理逻辑:
package main
import (
"fmt"
"github.com/DarthPestilane/easytcp"
"log"
)
func main() {
// 创建服务器
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.NewDefaultPacker(),
Codec: &easytcp.JsonCodec{},
})
// 添加全局中间件
s.Use(loggingMiddleware)
// 注册路由
s.AddRoute(1001, handleEcho, authMiddleware)
// 设置会话钩子
s.OnSessionCreate = func(session easytcp.Session) {
log.Printf("session created: %s", session.ID())
}
s.OnSessionClose = func(session easytcp.Session) {
log.Printf("session closed: %s", session.ID())
}
// 启动服务器
if err := s.Run(":5896"); err != nil {
log.Fatalf("serve error: %v", err)
}
}
// 处理函数
func handleEcho(c easytcp.Context) {
var reqData map[string]interface{}
if err := c.Bind(&reqData); err != nil {
c.SetResponse(500, map[string]string{"error": "invalid request"})
return
}
// 处理请求
respData := map[string]interface{}{
"code": 200,
"message": "success",
"data": reqData,
}
// 设置响应
if err := c.SetResponse(1002, respData); err != nil {
fmt.Printf("set response error: %v\n", err)
}
}
// 日志中间件
var loggingMiddleware easytcp.MiddlewareFunc = func(next easytcp.HandlerFunc) easytcp.HandlerFunc {
return func(c easytcp.Context) {
req := c.Request()
log.Printf("request received | id: %d | size: %d", req.ID(), len(req.Data()))
next(c)
resp := c.Response()
log.Printf("response sent | id: %d | size: %d", resp.ID(), len(resp.Data()))
}
}
// 认证中间件
var authMiddleware easytcp.MiddlewareFunc = func(next easytcp.HandlerFunc) easytcp.HandlerFunc {
return func(c easytcp.Context) {
// 这里可以添加认证逻辑
// 例如检查请求头或token等
next(c)
}
}
这个示例展示了:
- 创建带有JSON编解码器的服务器
- 添加全局日志中间件
- 注册带有认证中间件的路由处理器
- 设置会话生命周期钩子
- 完整的请求处理流程,包括请求解码和响应编码
EasyTCP提供了灵活的方式来构建TCP服务器,可以根据需要自定义打包器、编解码器和中间件,满足各种业务场景需求。
更多关于golang轻量级TCP服务器框架插件库easytcp的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang轻量级TCP服务器框架插件库easytcp的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Easytcp - 轻量级Golang TCP服务器框架
Easytcp是一个轻量级的Golang TCP服务器框架,它提供了简洁的API和良好的扩展性,适合快速构建高性能的TCP服务。下面我将详细介绍它的使用方法和示例代码。
安装
go get github.com/DarthPestilane/easytcp
快速开始
基本服务器示例
package main
import (
"fmt"
"github.com/DarthPestilane/easytcp"
)
func main() {
// 创建服务器
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.DefaultPacker{}, // 使用默认的数据包处理器
Codec: nil, // 不使用编解码器
})
// 注册路由
s.AddRoute("ping", func(c easytcp.Context) {
fmt.Println("received ping request")
c.SetResponse("pong", []byte("pong"))
})
// 启动服务器
if err := s.Run(":8080"); err != nil {
fmt.Println("server error:", err)
}
}
客户端示例
package main
import (
"fmt"
"github.com/DarthPestilane/easytcp"
)
func main() {
// 创建客户端
client := easytcp.NewClient(&easytcp.ClientOption{
Packer: easytcp.DefaultPacker{},
Codec: nil,
})
// 连接服务器
if err := client.Connect("localhost:8080"); err != nil {
fmt.Println("connect error:", err)
return
}
defer client.Close()
// 发送请求
resp, err := client.Send("ping", []byte("ping"))
if err != nil {
fmt.Println("send error:", err)
return
}
fmt.Printf("received response: %s\n", resp.Data())
}
核心功能
1. 路由处理
Easytcp支持基于消息ID的路由处理:
s.AddRoute("login", func(c easytcp.Context) {
// 处理登录逻辑
reqData := c.Request().Data()
fmt.Printf("received login request: %s\n", reqData)
// 设置响应
c.SetResponse("login_ack", []byte("login success"))
})
2. 中间件支持
// 全局中间件
s.Use(func(next easytcp.HandlerFunc) easytcp.HandlerFunc {
return func(c easytcp.Context) {
fmt.Println("before request")
next(c)
fmt.Println("after request")
}
})
// 路由级别中间件
s.AddRoute("auth", authHandler, authMiddleware)
func authMiddleware(next easytcp.HandlerFunc) easytcp.HandlerFunc {
return func(c easytcp.Context) {
// 验证token等逻辑
if !isValid(c.Request().Data()) {
c.SetResponse("auth_fail", []byte("authentication failed"))
return
}
next(c)
}
}
3. 自定义数据包格式
type CustomPacker struct{}
func (p CustomPacker) Pack(msg *easytcp.Message) ([]byte, error) {
// 自定义打包逻辑
}
func (p CustomPacker) Unpack(data []byte) (*easytcp.Message, error) {
// 自定义解包逻辑
}
// 使用自定义Packer
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: CustomPacker{},
})
4. 编解码器支持
type JSONCodec struct{}
func (c JSONCodec) Encode(v interface{}) ([]byte, error) {
return json.Marshal(v)
}
func (c JSONCodec) Decode(data []byte, v interface{}) error {
return json.Unmarshal(data, v)
}
// 使用JSON编解码器
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.DefaultPacker{},
Codec: JSONCodec{},
})
// 处理JSON请求
s.AddRoute("json_req", func(c easytcp.Context) {
var req struct {
Name string `json:"name"`
}
if err := c.Bind(&req); err != nil {
// 处理错误
}
resp := struct {
Greeting string `json:"greeting"`
}{
Greeting: "Hello " + req.Name,
}
c.SetResponse("json_resp", resp)
})
高级特性
1. 连接管理
// 获取所有连接
connections := s.Connections()
for _, conn := range connections {
fmt.Println("connection id:", conn.ID())
}
// 添加连接建立和关闭的钩子
s.OnConnectionCreate(func(conn easytcp.Connection) {
fmt.Println("new connection:", conn.ID())
})
s.OnConnectionClose(func(conn easytcp.Connection) {
fmt.Println("connection closed:", conn.ID())
})
2. 心跳检测
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.DefaultPacker{},
Codec: nil,
// 设置心跳检测间隔和超时
HeartBeatCheckInterval: time.Second * 5,
HeartBeatIdleTime: time.Second * 30,
})
3. 性能优化
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.DefaultPacker{},
Codec: nil,
// 设置工作池大小
WorkPoolSize: 1000,
// 设置读写缓冲区大小
ReadBufferSize: 4096,
WriteBufferSize: 4096,
})
实际应用示例
简单的聊天服务器
package main
import (
"fmt"
"github.com/DarthPestilane/easytcp"
"sync"
)
var (
clients = make(map[string]easytcp.Connection)
mu sync.RWMutex
)
func main() {
s := easytcp.NewServer(&easytcp.ServerOption{
Packer: easytcp.DefaultPacker{},
})
// 连接管理
s.OnConnectionCreate(func(conn easytcp.Connection) {
mu.Lock()
defer mu.Unlock()
clients[conn.ID()] = conn
fmt.Println("client connected:", conn.ID())
})
s.OnConnectionClose(func(conn easytcp.Connection) {
mu.Lock()
defer mu.Unlock()
delete(clients, conn.ID())
fmt.Println("client disconnected:", conn.ID())
})
// 注册消息处理
s.AddRoute("register", handleRegister)
s.AddRoute("message", handleMessage)
s.AddRoute("broadcast", handleBroadcast)
if err := s.Run(":8080"); err != nil {
fmt.Println("server error:", err)
}
}
func handleRegister(c easytcp.Context) {
username := string(c.Request().Data())
c.Session().Set("username", username)
c.SetResponse("register_ack", []byte("registered as "+username))
}
func handleMessage(c easytcp.Context) {
to := string(c.Request().Data()[:10]) // 假设前10字节是目标用户ID
msg := c.Request().Data()[10:] // 剩余部分是消息内容
mu.RLock()
defer mu.RUnlock()
if conn, ok := clients[to]; ok {
conn.Send("private_msg", []byte(fmt.Sprintf("%s: %s", c.Session().Get("username"), msg)))
c.SetResponse("msg_ack", []byte("message sent"))
} else {
c.SetResponse("msg_err", []byte("user not found"))
}
}
func handleBroadcast(c easytcp.Context) {
msg := fmt.Sprintf("[Broadcast] %s: %s", c.Session().Get("username"), c.Request().Data())
mu.RLock()
defer mu.RUnlock()
for _, conn := range clients {
conn.Send("broadcast_msg", []byte(msg))
}
c.SetResponse("broadcast_ack", []byte("broadcast sent"))
}
总结
Easytcp是一个轻量但功能齐全的Golang TCP框架,具有以下特点:
- 简洁易用的API设计
- 灵活的路由和中间件支持
- 可扩展的数据包处理和编解码
- 内置连接管理和心跳检测
- 高性能的工作池模型
它非常适合构建各种TCP服务,如游戏服务器、IoT设备通信、即时通讯系统等。通过合理的配置和扩展,可以满足大多数TCP应用场景的需求。