go开源库nano)
前言
最近感觉自己看书学习的时间太少了,需要补充能量,系统学习些东西。在学习golang,通过github上的这个nano库学习,可以利用golang把之前的业务流程从golang的角度看看。
nano
github:https://github.com/lonng/nano
文档是这样介绍的:
Nano是一个易于使用、快速、轻量级的游戏服务器网络库。它提供了一个核心网络体系结构以及一系列工具和库,可以帮助开发人员消除对公共底层逻辑的枯燥重复工作。NaNO的目标是通过消除重复网络相关编程所需的时间来提高开发效率。
Nano是为服务器端应用程序设计的,例如实时游戏、社交游戏、移动游戏等等。
安装“走起”
//安装
go get github.com/lonng/nano
# dependencies
go get -u github.com/golang/protobuf
go get -u github.com/gorilla/websocket
概念介绍
组件(Component)
nano应用是由一些松散耦合的Component组成的,每个Component完成一些功能。整个应用可以看作是一 个Component容器,完成Component的加载以及生命周期管理。每个Component往往有Init,AfterInit, BeforeShutdown,Shutdown等方法,用来完成生命周期管理。
type DemoComponent struct{}
func (c *DemoComponent) Init() {}
func (c *DemoComponent) AfterInit() {}
func (c *DemoComponent) BeforeShutdown() {}
func (c *DemoComponent) Shutdown() {}
Handler
Handler用来处理业务逻辑,Handler可以有如下形式的签名:
// 以下的Handler会自动将消息反序列化,在调用时当做参数传进来
func (c *DemoComponent) DemoHandler(s *session.Session, payload *pb.DemoPayload) error {
// 业务逻辑开始
// ...
// 业务逻辑结束
return nil
}
// 以下的Handler不会自动将消息反序列化,会将客户端发送过来的消息直接当作参数传进来
func (c *DemoComponent) DemoHandler(s *session.Session, raw []byte) error {
// 业务逻辑开始
// ...
// 业务逻辑结束
return nil
}
路由(Route)
route用来标识一个具体服务或者客户端接受服务端推送消息的位置,对服务端来说,其形式一般是…,例如 “Room.Message”, 在我们的示例中, Room是一个包含相关Handler的组件, Message是一个定义在 Room中的Handler, Room中所有符合Handler签名的方法都会在nano应用启动时自动注册.
对客户端来说,其路由一般形式为onXXX(比如我们示例中的onMessage),当服务端推送消息时,客户端会 有相应的回调。
会话(Session)
Session对应于一个客户端会话, 当客户端连接服务器后, 会建立一个会话, 会话在玩家保持连接期间可以 用于保存一些上下文信息, 这些信息会在连接断开后释放.
组(Group)
Group可以看作是一个Session的容器,主要用于需要广播推送消息的场景。可以把某个玩家的Session加 入到一个Group中,当对这个Group推送消息的时候,所有加入到这个Group的玩家都会收到推送过来的消 息。一个玩家的Session可能会被加入到多个Group中,这样玩家就会收到其加入的Group推送过来的消息。
请求(Request), 响应(Response), 通知(Notify), 推送(Push)
nano中有四种消息类型的消息,分别是请求(Request), 响应(Response), 通知(Notify)和推送(Push).
客户端发起Request到服务器端,服务器端处理后会给其返回响应Response;
Notify是客户端发给服务端的 通知,也就是不需要服务端给予回复的请求;
Push是服务端主动给客户端推送消息的类型。
例子
package main
import (
"fmt"
"log"
"net/http"
"github.com/lonnng/nano"
"github.com/lonnng/nano/component"
"github.com/lonnng/nano/serialize/json"
"github.com/lonnng/nano/session"
)
type (
// define component
Room struct {
component.Base
group *nano.Group
}
// protocol messages
UserMessage struct {
Name string `json:"name"`
Content string `json:"content"`
}
NewUser struct {
Content string `json:"content"`
}
AllMembers struct {
Members []int64 `json:"members"`
}
JoinResponse struct {
Code int `json:"code"`
Result string `json:"result"`
}
)
func NewRoom() *Room {
return &Room{
group: nano.NewGroup("room"),
}
}
func (r *Room) AfterInit() {
nano.OnSessionClosed(func(s *session.Session) {
r.group.Leave(s)
})
}
// Join room
func (r *Room) Join(s *session.Session, msg []byte) error {
s.Bind(s.ID()) // binding session uid
s.Push("onMembers", &AllMembers{Members: r.group.Members()})
// notify others
r.group.Broadcast("onNewUser", &NewUser{Content: fmt.Sprintf("New user: %d", s.ID())})
// new user join group
r.group.Add(s) // add session to group
return s.Response(&JoinResponse{Result: "sucess"})
}
// Send message
func (r *Room) Message(s *session.Session, msg *UserMessage) error {
return r.group.Broadcast("onMessage", msg)
}
func main() {
nano.Register(NewRoom())
nano.SetSerializer(json.NewSerializer())
nano.EnableDebug()
log.SetFlags(log.LstdFlags | log.Llongfile)
http.Handle("/web/", http.StripPrefix("/web/", http.FileServer(http.Dir("web"))))
nano.SetCheckOriginFunc(func(_ *http.Request) bool { return true })
nano.Listen(":3250", nano.WithIsWebsocket(true))
}
每个需要对外提供服务的Component 都需要通过Register 注册到主服务,通过把 component 分解成Service ,然后符合条件的hander解析保存到 Service 。hander是处理具体逻辑的单元。
通过这个有一个初步了解,下次会接着分析一个聊天的程序。