golang高性能游戏服务器网络框架插件库gnet的使用

golang高性能游戏服务器网络框架插件库gnet的使用

特性

  • 多线程、非阻塞
  • 默认支持protobuf
  • 使用无锁RingBuffer优化接收和分发,某些情况下性能可提升5倍
  • 易于实现自定义编码和解码
  • 支持RPC
  • 支持TCP、WebSocket(ws和wss)

使用示例

运行服务器

// 创建protobuf编解码器
codec := gnet.NewProtoCodec(nil)
// 创建默认连接处理器
handler := gnet.NewDefaultConnectionHandler(codec)
// 注册消息处理函数
handler.Register(gnet.PacketCommand(pb.CmdTest_Cmd_TestMessage), onTestMessage, new(pb.TestMessage))

// 配置监听器
listenerConfig := &gnet.ListenerConfig{
    AcceptConfig: gnet.DefaultConnectionConfig,
}
listenerConfig.AcceptConfig.Codec = codec
listenerConfig.AcceptConfig.Handler = handler

// 创建监听器
gnet.GetNetMgr().NewListener(ctx, "localhost:10001", listenerConfig)

运行客户端

// 创建protobuf编解码器
codec := gnet.NewProtoCodec(nil)
// 创建默认连接处理器
handler := gnet.NewDefaultConnectionHandler(codec)
// 注册消息处理函数
handler.Register(gnet.PacketCommand(pb.CmdTest_Cmd_TestMessage), onTestMessage, new(pb.TestMessage))

// 配置连接
connectionConfig := gnet.DefaultConnectionConfig
connectionConfig.Codec = clientCodec
connectionConfig.Handler = clientHandler

// 创建连接器并发送消息
connector := gnet.GetNetMgr().NewConnector(ctx, "localhost:10001", &connectionConfig, nil)
connector.SendPacket(gnet.NewProtoPacket(gnet.PacketCommand(pb.CmdTest_Cmd_TestMessage),
    &pb.TestMessage{
        Name: "hello",
    }))

编码和解码

gnet将TCP流的分包解码分为三层:

  1. 分包流层:格式为|Length|Data|,接收完整包内容后交给下一层处理
  2. 数据解码层:对第一层的数据进行解码,如解密、解压等
  3. protobuf反序列化层:生成proto.Message

length & data encode decode

使用RingBuffer提升性能

ringbuffer-performance

RPC

RPC向目标发送请求并阻塞等待回复,类似于grpc-go,但gnet使用命令ID而不是方法名

request := gnet.NewProtoPacket(cmd, &pb.HelloRequest{
    Name: "hello",
})
reply := new(pb.HelloReply)
err := connection.Rpc(request, reply)
if err != nil {
    return
}
logger.Info("reply:%v", reply)

Goroutine

connection_goroutine

示例

  • example/helloworld: 使用protobuf消息的简单示例
  • example/data_packet: 使用DataPacket的简单示例
  • example/custom_packet: 如何扩展自定义包结构
  • example/tcp_connection_simple: 不使用RingBuffer的protobuf消息示例
  • example/packet_size: 发送大于RingBuffer容量的大包
  • example/websocket: WebSocket简单示例
  • example/rpc: 如何使用RPC
  • example/simulate_game: 游戏应用场景的性能测试

客户端连接库

C#: gnet_csharp

项目

gnet也被用于我们的商业在线游戏项目中


更多关于golang高性能游戏服务器网络框架插件库gnet的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高性能游戏服务器网络框架插件库gnet的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


gnet - 高性能Go语言游戏服务器网络框架

gnet是一个轻量级、高性能、基于事件驱动的Go语言网络框架,特别适合游戏服务器、即时通讯等需要高并发低延迟的场景。下面我将详细介绍gnet的使用方法。

gnet核心特性

  1. 基于事件驱动,非阻塞IO
  2. 支持多线程/多核处理
  3. 内存池优化,减少GC压力
  4. 简单易用的API接口
  5. 高性能,可处理数十万并发连接

基本使用示例

安装gnet

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
	
	// 打印日志
	log.Printf("Echo: %s", string(data))
	
	return
}

func main() {
	echo := new(echoServer)
	
	// 启动服务器
	err := gnet.Serve(echo, "tcp://:9000", gnet.WithMulticore(true))
	if err != nil {
		log.Fatal(err)
	}
}

核心API详解

事件处理接口

gnet通过实现以下接口来处理各种网络事件:

type EventServer interface {
	// 服务器启动时调用
	OnInitComplete(server Server) (action Action)
	
	// 新连接建立时调用
	OnOpened(c Conn) (out []byte, action Action)
	
	// 连接关闭时调用
	OnClosed(c Conn, err error) (action Action)
	
	// 接收到数据时调用
	React(c Conn) (out []byte, action Action)
	
	// 定时器触发时调用
	Tick() (delay time.Duration, action Action)
}

完整游戏服务器示例

package main

import (
	"log"
	"time"

	"github.com/panjf2000/gnet"
)

type gameServer struct {
	*gnet.EventServer
	players map[string]gnet.Conn
}

func (gs *gameServer) OnInitComplete(srv gnet.Server) (action gnet.Action) {
	log.Printf("Game server started on %s (multi-core: %t, loops: %d)",
		srv.Addr.String(), srv.Multicore, srv.NumEventLoop)
	
	// 初始化玩家列表
	gs.players = make(map[string]gnet.Conn)
	
	return
}

func (gs *gameServer) OnOpened(c gnet.Conn) (out []byte, action gnet.Action) {
	// 新玩家连接
	playerID := c.RemoteAddr().String()
	gs.players[playerID] = c
	
	log.Printf("Player connected: %s", playerID)
	
	// 发送欢迎消息
	out = []byte("Welcome to the game server!\n")
	return
}

func (gs *gameServer) OnClosed(c gnet.Conn, err error) (action gnet.Action) {
	// 玩家断开连接
	playerID := c.RemoteAddr().String()
	delete(gs.players, playerID)
	
	log.Printf("Player disconnected: %s", playerID)
	return
}

func (gs *gameServer) React(c gnet.Conn) (out []byte, action gnet.Action) {
	data := c.Read()
	playerID := c.RemoteAddr().String()
	
	// 处理游戏指令
	cmd := string(data)
	switch cmd {
	case "ping\n":
		out = []byte("pong\n")
	case "time\n":
		out = []byte(time.Now().String() + "\n")
	case "players\n":
		out = []byte(fmt.Sprintf("Online players: %d\n", len(gs.players)))
	default:
		out = []byte("Unknown command\n")
	}
	
	log.Printf("Player %s sent: %s", playerID, cmd)
	return
}

func (gs *gameServer) Tick() (delay time.Duration, action gnet.Action) {
	// 每秒广播一次在线玩家数
	msg := fmt.Sprintf("Current online players: %d\n", len(gs.players))
	for _, conn := range gs.players {
		_ = conn.AsyncWrite([]byte(msg))
	}
	
	return time.Second, gnet.None
}

func main() {
	gs := &gameServer{}
	
	// 启动服务器,配置多核处理
	err := gnet.Serve(gs, "tcp://:9000",
		gnet.WithMulticore(true),
		gnet.WithTCPKeepAlive(time.Minute*5),
		gnet.WithCodec(&gnet.LineBasedFrameCodec{}),
	)
	
	if err != nil {
		log.Fatal(err)
	}
}

高级配置选项

gnet提供了多种配置选项来优化性能:

err := gnet.Serve(server, addr,
	gnet.WithMulticore(true),          // 多核并行处理
	gnet.WithReusePort(true),          // 端口复用
	gnet.WithTCPKeepAlive(time.Minute), // TCP保活
	gnet.WithCodec(codec),             // 自定义编解码器
	gnet.WithSocketRecvBuffer(1024),   // 接收缓冲区大小
	gnet.WithSocketSendBuffer(1024),   // 发送缓冲区大小
	gnet.WithTicker(true),             // 启用定时器
	gnet.WithLogLevel(logging.Info),   // 日志级别
)

性能优化建议

  1. 启用多核处理WithMulticore(true)可以充分利用多核CPU
  2. 使用连接池:复用连接减少GC压力
  3. 合理设置缓冲区:根据消息大小调整收发缓冲区
  4. 批量处理消息:合并小包减少系统调用
  5. 避免内存拷贝:尽量复用内存,减少分配

总结

gnet是一个非常适合游戏服务器开发的Go语言网络框架,它提供了简洁的API和高性能的事件驱动模型。通过合理配置和使用,可以轻松构建出支持数十万并发连接的游戏服务器。相比标准库net和大多数Go网络框架,gnet在性能上有明显优势,特别适合对延迟敏感的游戏服务器场景。

实际项目中,你可以基于gnet构建更复杂的游戏协议处理、房间管理、玩家状态同步等功能,gnet提供的基础设施已经为高性能网络通信打下了良好基础。

回到顶部