Go 游戏服务器入门文档:如何构建你的第一个 nano 应用 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
chrislon
V2EX    问与答

Go 游戏服务器入门文档:如何构建你的第一个 nano 应用

  •  
  •   chrislon 2017-08-15 21:19:04 +08:00 4011 次点击
    这是一个创建于 2983 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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有一些自己的术语,这里先对术语做一些简单的解释,给读者一个直观的概念,不至于看到相应术语时产生 迷惑。

    组件(Component)

    nano应用是由一些松散耦合的Component组成的,每个Component完成一些功能。整个应用可以看作是一 个Component容器,完成Component的加载以及生命周期管理。每个Component往往有InitAfterInitBeforeShutdownShutdown等方法,用来完成生命周期管理。

    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是服务端主动给客户端推送消息的类型。在后面的叙述中,将 会使用这些术语而不再作解释。

    示例开始

    Server

    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") } 
    1. 首先, 导入这个代码片段需要应用的包
    2. 定义Room组件
    3. 定义所有全后端交互可能用到的协议结构体(实际项目中可能使用 Protobuf)
    4. 定义所有的 Handler, 这里包含JoinMessage
    5. 启动我们的应用
      • 注册组件
      • 设置序列化反序列器
      • 开启调试信息
      • 设置 log 输出信息
      • Set WebSocket check origin function
      • 开始监听WebSocket地址":3250"

    Client

    参考各个客户端 SDK 文档

    Summary

    这部分, 我们构建了一个简单的聊天应用, 并对代码做了简单的介绍, 通过这个教程, 相信读者对nano的工作 流程和工作机制有了一个初步的了解.

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3106 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 12:06 PVG 20:06 LAX 05:06 JFK 08:06
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86