https://github.com/lonnng/nano/blob/master/docs/get_started_zh_CN.md
--- 文档复制于 2017-08-18,最新内容请参考最新地址----
nano
应用在这个教程中,我们将构建一个基于浏览器和WebSocket
的聊天应用。
由于游戏在场景管理、客户端动画等方面有一定的复杂性,并不适合作为nano
的入门应用。对于大多数开发者
而言,普通聊天室是一个更加适合入门nano
的应用。
nano
是一个轻量级的服务器框架,它最适合的应用领域是网页游戏、社交游戏、移动游戏的服务端。当然还不
仅仅是游戏,用nano
开发高实时 web 应用也非常合适。
本教程适用于对nano
零基础的用户,如果你已经有过一定的nano
开发基础,请跳过这个教程,你可以阅读
开发指南,那里会对一些话题作较为详细的探讨。
由于nano
是基于 Go 开发的,因此希望你在阅读本教程前对 Go 语言有一些了解。
本教程的示例源码放在 github 上完整代码
本教程将以一个实时聊天应用为例子,通过对这个应用进行不同的修改来展示nano
框架的一些功能特性,让用
户能大致了解nano
,熟悉并能够使用nano
进行应用程序的开发。
本教程假定你使用的开发环境是类 Unix 系统,如果你使用的 Windows 系统,希望你能够知道相关的对应方式,比 如一些.sh 脚本,在 Windows 下会使用一个同名的 bat 文件,本教程中对于 Windows 系统,不做特殊说明。
nano
有一些自己的术语,这里先对术语做一些简单的解释,给读者一个直观的概念,不至于看到相应术语时产生
迷惑。
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 会自动将消息反序列化,在调用时当做参数传进来
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 用来标识一个具体服务或者客户端接受服务端推送消息的位置,对服务端来说,其形式一般是..,例如
"Room.Message", 在我们的示例中, Room
是一个包含相关Handler
的组件, Message
是一个定义在
Room
中的Handler
, Room
中所有符合Handler
签名的方法都会在nano
应用启动时自动注册.
对客户端来说,其路由一般形式为 onXXX(比如我们示例中的 onMessage),当服务端推送消息时,客户端会 有相应的回调。
Session
对应于一个客户端会话, 当客户端连接服务器后, 会建立一个会话, 会话在玩家保持连接期间可以
用于保存一些上下文信息, 这些信息会在连接断开后释放.
Group
可以看作是一个Session
的容器,主要用于需要广播推送消息的场景。可以把某个玩家的Session
加
入到一个Group
中,当对这个Group
推送消息的时候,所有加入到这个Group
的玩家都会收到推送过来的消
息。一个玩家的Session
可能会被加入到多个Group
中,这样玩家就会收到其加入的Group
推送过来的消息。
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.ListenWS(":3250")
}
Room
组件Join
和Message
WebSocket
地址":3250"参考各个客户端 SDK 文档
这部分, 我们构建了一个简单的聊天应用, 并对代码做了简单的介绍, 通过这个教程, 相信读者对nano
的工作
流程和工作机制有了一个初步的了解.