gnet - Go语言高性能非阻塞事件驱动网络框架
gnet是一个基于事件驱动的轻量级高性能网络框架,它直接使用epoll(kqueue)系统调用来实现非阻塞I/O,避免了标准库net的goroutine-per-connection模型带来的高内存消耗问题。
主要特性
- 基于事件驱动的异步非阻塞网络模型
- 支持多线程/多核处理
- 内置负载均衡算法
- 支持多种协议(TCP、UDP、Unix Domain Socket)
- 高性能,低延迟
- 简洁易用的API接口
安装
go get -u github.com/panjf2000/gnet
基本使用示例
简单的Echo服务器
package main
import (
"log"
"github.com/panjf2000/gnet"
)
type echoServer struct {
*gnet.EventServer
}
func (es *echoServer) React(c gnet.Conn) (out []byte, action gnet.Action) {
// 读取客户端数据
data := c.Read()
// 将数据原样返回
out = data
// 更新缓冲区
c.ResetBuffer()
return
}
func main() {
echo := new(echoServer)
// 启动服务器
err := gnet.Serve(echo, "tcp://:9000", gnet.WithMulticore(true))
if err != nil {
log.Fatal(err)
}
}
更完整的TCP服务器示例
package main
import (
"log"
"time"
"github.com/panjf2000/gnet"
)
type tcpServer struct {
*gnet.EventServer
}
func (ts *tcpServer) OnInitComplete(srv gnet.Server) (action gnet.Action) {
log.Printf("TCP server is listening on %s (multi-cores: %t, loops: %d)\n",
srv.Addr.String(), srv.Multicore, srv.NumEventLoop)
return
}
func (ts *tcpServer) OnOpened(c gnet.Conn) (out []byte, action gnet.Action) {
log.Printf("Connection opened: %s", c.RemoteAddr().String())
return
}
func (ts *tcpServer) OnClosed(c gnet.Conn, err error) (action gnet.Action) {
log.Printf("Connection closed: %s, error: %v", c.RemoteAddr().String(), err)
return
}
func (ts *tcpServer) React(c gnet.Conn) (out []byte, action gnet.Action) {
data := c.Read()
// 业务逻辑处理
response := processData(data)
// 发送响应
out = response
// 更新缓冲区
c.ResetBuffer()
return
}
func processData(data []byte) []byte {
// 这里添加你的业务逻辑
return []byte("Processed: " + string(data))
}
func main() {
tcp := &tcpServer{}
// 启动服务器,配置多核处理
err := gnet.Serve(tcp, "tcp://:9000",
gnet.WithMulticore(true),
gnet.WithReusePort(true),
gnet.WithTCPKeepAlive(time.Minute*5),
gnet.WithLogLevel(gnet.DebugLevel))
if err != nil {
log.Fatal(err)
}
}
高级特性
定时任务
func (ts *tcpServer) Tick() (delay time.Duration, action gnet.Action) {
log.Println("This is a tick event")
return time.Second * 5, gnet.None
}
自定义编解码器
type myCodec struct{}
func (mc *myCodec) Encode(c gnet.Conn, buf []byte) ([]byte, error) {
// 自定义编码逻辑
return buf, nil
}
func (mc *myCodec) Decode(c gnet.Conn) ([]byte, error) {
// 自定义解码逻辑
return c.Read(), nil
}
// 使用时
err := gnet.Serve(echo, "tcp://:9000",
gnet.WithCodec(&myCodec{}))
性能优化建议
- 启用多核处理:
gnet.WithMulticore(true)
- 调整事件循环数量:
gnet.WithNumEventLoop(runtime.NumCPU())
- 使用连接池管理连接
- 避免在React函数中进行耗时操作
- 合理设置读写缓冲区大小
与标准库net对比优势
- 更高的吞吐量:gnet可以处理更多的并发连接
- 更低的内存消耗:避免了goroutine-per-connection模型
- 更低的延迟:基于事件驱动的模型响应更快
- 更好的多核利用率:内置负载均衡算法
适用场景
- 高并发TCP/UDP服务器
- 游戏服务器
- 即时通讯服务
- 代理服务器
- 需要高性能网络处理的任何场景
gnet特别适合需要处理大量并发连接但对每个连接处理逻辑相对简单的场景,对于复杂业务逻辑的场景,可能需要结合其他框架或组件使用。