跟炒鸡辣鸡一起学用go写游戏后端

几个月前,把java分布式游戏后端研究了一遍,仿照现成的架构写了两套游戏出来。但是我的脚步并未停下,现在开始研究如何用Go语言搭建游戏后端。

1、设计前后端交互的方式
之前的java我用到了netty+protobuf和前端进行交互,而游戏服务之间采用RPC(远程过程调用)的方式进行通信。netty是java网络编程中一种比较优秀的网络通信框架,采用的是select事件驱动模式,这种轮询的方式尽管有些落后,但是相比于同步NIO的通信方式,性能还是有大幅度的提升。
在go中,一般使用net/http来建立和远程客户端的通信,搭配webSocket来接收并处理远程的请求。一个用net/http来搭建服务器的例程如下:

package main
import (
    "fmt"
    "net/http"
    "log"
)
func HandleIndex(w http.ResponseWriter, r *http.Request) {
    r.ParseForm()
    fmt.Println("PATH: ", r.URL.Path)
    fmt.Println("SCHEME: ", r.URL.Scheme)
    fmt.Println("METHOD: ", r.Method)
    fmt.Println()
    fmt.Fprintf(w, "<h1>Index Page</h1>")
}
func main() {
    http.HandleFunc("/", HandleIndex)
    err := http.ListenAndServe(":8000", nil)
    if err != nil {
        log.Fatal("ERROR: ", err)
    }
}

我把这段代码解析一下:

http.HandleFunc("/", HandleIndex)
//注册处理类,即表示如果收到根目录的请求,就使用HandleIndex这个方法来解决
http.ListenAndServe(":8000", nil)
//服务监听8000端口

用go搭建一个demo服务器博客入口

2、包net/http中嵌入websocket包的方法:

http.Handle("/xss/", websocket.Server{Handler: s.handleClient, Handshake: nil})

确定了前后端走通过http和websocket之后,可以使用mux包来定义处理路由

//导入方法:
imposrt "github.com/gorilla/mux"
//使用方法:
r := mux.NewRouter()
http.Handle("/", r)

//定义mux
func registerHttpHandlers(r *mux.Router) {
    r.HandleFunc("/v123/plat/userInfo", web.WebUserInfoHandler)
    r.HandleFunc("/v123/plat/userCharge", web.WebChangeCardHandler)
}
//需要使用路由的时候只需要调用
registerHttpHandlers(r)
//就可以了

除了显式的调用路由处理的方法来预定义处理类,还可以定义数据包的格式来接收和处理前端的请求。首先,定义一个枚举类型来表示消息类型:

const (
    MessageId_LOGIN                           = 1  //登录
    MessageId_HEART_BEAT                      = 2  //心跳
    MessageId_RECONNECT                       = 3  //重连
    MessageId_CREATE_ROOM                     = 4  //创建房间
    MessageId_ENTER_ROOM                      = 5  //进入房间
    MessageId_ENTER_ROOM_NOTIFY               = 6  //进入房间通知
    MessageId_BACK_ROOM                       = 7  //返回房间信息
    MessageId_DISMISS_ROOM_REQ                = 8  //解散房间请求
    MessageId_DISMISS_ROOM_NOTIFY             = 9  //解散请求房间广播
    MessageId_DISMISS_ROOM_USER_RESULT        = 10 //其他玩家的处理结果
    MessageId_DISMISS_ROOM_USER_RESULT_NOTIFY = 11 //其他玩家的处理结果广播
    MessageId_DISMISS_ROOM_RESULT_NOTIFY      = 12 //解散房间成功通知
    MessageId_LEAVE_ROOM                      = 13 //退出房间
    MessageId_LEAVE_ROOM_NOTIFY               = 14 //退出房间广播
    MessageId_BACK_ROOM_NOTIFY                = 15 //返回房间广播
    MessageId_START_GAME                      = 16 //游戏开始
    ...
)

定义了消息类型之后,就可以来注册处理类了,可以自行设计一个集合,以键值对的方式,将消息类型的枚举值作为key,而处理方法作为value,每次接收到message后可以自动响应出解决的方法。

func registerUserHandlers() {
    GetMsgRegistry().RegisterUnLoginMsg(int32(util.MessageId_LOGIN))
    GetMsgRegistry().RegisterUnLoginMsg(int32(util.MessageId_WECHAT_LOGIN))
    GetMsgRegistry().RegisterUnLoginMsg(int32(util.MessageId_ACCESSTOKEN_LOGIN))
    GetMsgRegistry().RegisterMsg(int32(util.MessageId_LOGIN), user.LoginHandler)
    GetMsgRegistry().RegisterMsg(int32(util.MessageId_CREATE_ROOM), user.CreateRoomHandler)
    GetMsgRegistry().RegisterMsg(int32(util.MessageId_ENTER_ROOM), user.EnterRoomHandler)
    GetMsgRegistry().RegisterMsg(int32(util.MessageId_BACK_ROOM), user.BackRoomHandler)
}

然后等到收到前端的请求之后就可以使用类似于

func (registry *MsgRegistry) getHandler(msgId int32) func(msg *server.ClientMsg, sess *server.Session) []byte {
    registry.mu.RLock()
    defer registry.mu.RUnlock()
    fmt.Print(msgId)
    fmt.Print("\n")
    return registry.registry[msgId]
}

这样的方法取出来。这样设计并接收前端请求的架构就已经搭建好了。

猜你喜欢

转载自blog.csdn.net/xielinrui123/article/details/80658293