A pragmatic game server framework in Go (golang).
- Extremely easy to use
- Reliable
- Multicore support
- Modularity
Leaf is licensed under the Apache License, Version 2.0. See LICENSE for the full license text.
A game server framework in Go (golang)
License: Apache License 2.0
首先感谢作者的开源精神!个人在使用leaf过程中提交点小建议。
感觉目前的定时器功能还不够,有个常见的需求不具备,说明如下:
根据指定定时器名称,可设置时间间隔,定时轮训执行某个func(),以此创建定时器触发器。
并提供相关的查询、修改时间间隔、停止、清理等相关接口。
需要注意的是,需要从整体去规划定时器的触发,而不是任意创建一个定时器就等待它自己内部按自己内部的时间触发。例如,创建一个房间,房间会按每秒50次触发房间广播的定时轮询触发器A,如果有100个房间总不能100个定时器吧?应该是100个房间都在定时轮询触发器A内触发吧。
个人拙见,见效勿怪。
目录生成目录默认是main.go文件所在目录,而不是生成在bin目录下
写个框架深度源码剖析 就更好了 对于新手学习 谢谢楼主 谢谢大神
分别调用 Agent.Close(), Agent.Destroy(),或者一起调用,都会有日志:
[debug ] read message: read tcp 127.0.0.1:9999->127.0.0.1:60990: use of closed network connection
Wiki文档中并没有提供相关代码,只好硬着头皮自己写
conn, err := net.Dial("tcp", "127.0.0.1:3563")
if err != nil {
panic(err)
}
hello := &msg.Hello{
Name: proto.String("leaf"),
}
data, err := proto.Marshal(hello)
if err != nil {
log.Fatal("marshaling error: ", err)
}
// len + data
m := make([]byte, 2+len(data))
// 默认使用大端序
binary.BigEndian.PutUint16(m, uint16(len(data)))
copy(m[2:], data)
// 发送消息
conn.Write(m)
服务端打印:
2016/12/16 21:04:35 [debug ] unmarshal message error: message id 2564 not registered
不知道该怎么办了
例如:自己写了个战斗模块进行计算,多个玩家同时请求是否会出现并发问题?
type Processor struct {
msgInfo map[string]*MsgInfo
}
type MsgInfo struct {
msgType reflect.Type
msgRouter *chanrpc.Server
msgHandler MsgHandler
msgRawHandler MsgHandler
}
这两个msgInfo 是通过大小写来区分的,容易混淆,上面msgInfo 改成 msgMap 之类比较好。
func GetToken(length int) string {
str := ""
for i := 0; i < length; i++ {
str += RandString()
}
return str
}
// 生成随机字符
func RandString() string {
str := [...]string{
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c",
"d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p",
"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C",
"D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "~", "!", "@",
"#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "=", "+", "[",
"]", "{", "}", "|", "<", ">", "?", "/", ".", ",", ";", ":"}
rand.Seed(time.Now().UnixNano())
return str[rand.Int63n(int64(len(str)))]
}
类似于生成随机字符串这样的工具函数,放在哪里会比较好一点,新建一个util目录然后再新建一个util.go?
socket 可以通过 LINGER 选项设置关闭时(close 和 shutdown)的行为(http://man7.org/linux/man-pages/man7/socket.7.html ),如果开启了 LINGER 则会尽可能的发送已经进入队列中的消息:
在 Leaf 的网络层中,有一个类似的机制,但是和 socket 的行为有一些细微的差别:没有超时机制,在一些情况可能导致无限制的等待队列中的消息被发送。换而言之:
在 login/internal/module.go 中声明了var mongoDB *mongodb.DialContext
,并且在 OnInit 中连接成功。但在 login/internal/session.go 中 mongoDB为nil, session.go 的接口是由 hanlder.go 调用的。
module.go 相关代码:
var (
mongoDB *mongodb.DialContext
skeleton = base.NewSkeleton()
ChanRPC = skeleton.ChanRPCServer
)
type Module struct {
*module.Skeleton
}
func (m *Module) OnInit() {
m.Skeleton = skeleton
mongoDB, err := mongodb.Dial(conf.Server.DBUrl, 1024)
if err != nil {
log.Fatal("dial mongoDB error: %v", err)
panic(1)
}
log.Release("Connected to mongoDB by " + conf.Server.DBUrl)
err = mongoDB.EnsureUniqueIndex("game", "user", []string{"UserID"})
if err != nil {
log.Fatal("ensure index error: %v", err)
panic(1)
}
err = mongoDB.EnsureCounter("game", "counter", "user")
if err != nil {
log.Fatal("ensure counter error: %v", err)
panic(1)
}
}
session.go 相关代码:
func login(auth *msg.C2S_Auth, agent gate.Agent) (session *Session, err error) {
userID := auth.UserID
session = new(Session)
err = nil
log.Debug("mongoDB: %+v", mongoDB)
// ...
}
handler.go 相关代码:
func handleAuth(args []interface{}) {
m := args[0].(*msg.C2S_Auth)
a := args[1].(gate.Agent)
log.Debug("hello %v", m.UserID)
ssn := sessions[m.UserID]
if ssn != nil {
// kick
ssn.logout()
} else {
ssn, err := login(m, a)
if err != nil {
sessions[ssn.UserID] = ssn
}
}
// ...
}
说明太少了,按介绍中WebSocket的使用,实现从html5客户端向服务端发送信息,并在服务端debug出信息。可是我想在html5的页面中得到返回来的信息,而不是只是debug在服务端。。应该怎么做呢?请大神帮助。
| => ./server
2015/09/24 19:25:00 [release] Leaf starting up
2015/09/24 19:25:05 [debug ] read message error: EOF
2015/09/24 19:25:05 [debug ] hello leaf
看了几个golang game server后我觉得leaf最有条理性。首先感谢分享。
我在使用你的leaf server示例代码时,发现每次收包会有 EOF错误(但不影响主逻辑)
我对golang不熟,利用各种方法(包括gdb)弄了半天没搞清楚是哪里错了,原先以为是客户端write后没有close connection,但是close了还是报错,只能麻烦你帮忙解答下了,谢谢。
Could you comment your code for using in godoc? The documentation would help to work
gopkg.in/mgo.v2 的 mgo.Session 被封装起来了,而 Login 接口没有开放出来。
该怎么做 auth 呢?
实现权限管理有什么比较好的方式
在你们群里呆了一段时间,本来是想看看有什么好的建议及**我能吸取下,有什么见解也能听到,但是没想到好多都是带着程序员高傲光环说话,人家反馈了一个现实结果群里就一堆类似小学生的吐槽,建议清理下,本人已经退群!这个东西和pomelo还是挺类似的,pomelo的群非常好,对于同一个问题的反馈有完全不同的反响!你的这个群里面最好也能管理完善一下,不太建议为了人气什么人都加!
在msg/msg.go中,
const (
S2C_Auth_OK = 0
S2C_Auth_AccIDInvalid = 1
)
type S2C_Auth struct {
Err int
}
在game/internal/userdata.go中,
type UserData struct {
UserID int "_id"
AccID string
}
想让S2C_Auth添加UserData,
type S2C_Auth struct {
Err int
Data UserData
}
该如何处理,还是说消息结构体中只能是string、int、bool、[]string、[]int基本数据类型?
由于项目里没用用json和protobuf,用的是二进制的通信格式,急迫需要binary类型的处理,求增加此类型。
@name5566 能说一下 skeleton.NewLinearContext() 的具体用法?看得不怎么懂呀!麻烦
文档 :https://golang.org/pkg/reflect/#Value.Set
func (v Value) Set(x Value)
Set assigns x to the value v. It panics if CanSet returns false. As in Go, x's value must be assignable to v's type.
目前我的办法是在deepCopy
函数最前面加上CanSet
的判断
func deepCopy(dst, src reflect.Value) {
if !dst.CanSet() {
return
}
希望能完善一下文档,多写一些例子
可以添加对mysql的支持吗
客户端向Leaf发送消息,Leaf如何获得客户端的ip地址?
1、比如游戏并发访问比较高时,需要部署一个Login及多台Gate和Game模块,如何实现?
不同的用户登录到了不同的服务器,是否可实现广播消息?
2、游戏本身的数据保存到mysql,而不是mongodb, 需要如何扩展?
我想自己实现通信协议
推荐用长连接还是短连接?心跳包要自己处理吗?粘包是自己处理还是框架自带?
当使用WebSocket进行通讯时,手动关闭客户端,服务端能够监听到客户端关闭。如何客户端突然网络异常,比如手动关闭网络连接,服务端将收不到客户端的任何请求,这种情况下服务端要如何处理才能知道客户端已经断开连接?
I've seen this project at awesome-go. Unfortunately it's description doesn't help much about describing itself and it's features.
Does It handle web-sockets? It stores users data? It has an REST API?
I would love to contribute in some way.
Thank you
mutex只为同步一个closeFlag变量,更改为atomic是否会好一点?
defer is function scope, maybe sync.atomic is better for sync.Mutex?
比如一个模块挂掉了,是否有必要通过控制台在把服务启动起来!以及 模块中是否有线程死锁,如何让底层暴露信息出来?
解析器没有提供一个统一的littleEndian 会造成发送流 和 接收流 编码不一致
你的demo 中指涉及到json的数据格式 如果是二进制的数据格式 就很容易造成问题
也许是因为我对这个框架的认知度不够高 有些设计**上可能没有明白过来
在 #19 中讲到,服务器回应的是二进制数据,那么在Unity中如何解析二进制数据,目前用的是BestHttp
比如我要接入微信支付、支付宝,要访问一些http/https的接口,是直接用Go提供的net/http包吗?
目前想到的是在 rpcNewAgent,rpcCloseAgent 时维护用户 session,然后在每个 message 的 handle 函数开头做判断。
但这样做一个是重复操作,应该有一个统一的地方处理。二个是如果遗漏了,忘记判断,那么没验证的用户请求也能进入GameModule。
输出的文件名总是log.go, 这没有什么意义, 要定位到更上层的调用啊
把 game/internal 里面的 module.go 移动到与 internal 同级的新建 base 文件夹,结果只有 base 文件夹下的go文件的init()执行。internal 里面的不执行了。
是什么原因?
目前想到的是使用原生的"net/rpc",Leaf 有提供其他的方法吗?
我想实现用户登录的功能,然后将用户信息记录到数据库中,该如何实现,相关的介绍有点少
在 server/game/internal/ 目录下,创建与game.go 同级目录的 game_test.go,运行 go test 报错。
在server/game/internal/ 目录下创建 ./conf/server.json 能解决问题。但显然是不合理的做法。
求解。
Hi. I'm trying to implement authentication into my game server with a username and password. What is the best practice for doing this in Leaf?
(I'm sorry if this is the wrong place to ask. I'm just kinda stuck with doing this in my application.)
现在苹果要求必须用 https,而 https 页面里必须用 wss 连接,建议添加一下。
如题,之前出现的奇怪io现象。。有点诡异。
先留个问题记录。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.