origin 游戏服务器引擎简介

origin 是一个由 Go 语言(golang)编写的分布式开源游戏服务器引擎。origin适用于各类游戏服务器的开发,包括 H5(HTML5)游戏服务器。

origin 解决的问题:

  • origin总体设计如go语言设计一样,总是尽可能的提供简洁和易用的模式,快速开发。
  • 能够根据业务需求快速并灵活的制定服务器架构。
  • 利用多核优势,将不同的service配置到不同的node,并能高效的协同工作。
  • 将整个引擎抽象三大对象,node,service,module。通过统一的组合模型管理游戏中各功能模块的关系。
  • 有丰富并健壮的工具库。

Hello world!

下面我们来一步步的建立origin服务器,先下载origin引擎,或者使用如下命令:

go get -v -u  github.com/duanhf2012/origin

于是下载到GOPATH环境目录中,在src中加入main.go,内容如下:

package mainimport ("github.com/duanhf2012/origin/node"
)func main() {node.Start()
}

一个origin进程需要创建一个node对象,Start开始运行。您也可以直接下载origin引擎示例:

go get -v -u github.com/duanhf2012/originserver

本文所有的说明都是基于该示例为主。

origin引擎三大对象关系

  • Node: 可以认为每一个Node代表着一个origin进程
  • Service:一个独立的服务可以认为是一个大的功能模块,他是Node的子集,创建完成并安装Node对象中。服务可以支持对外部RPC等功能。
  • Module: 这是origin最小对象单元,强烈建议所有的业务模块都划分成各个小的Module组合,origin引擎将监控所有服务与Module运行状态,例如可以监控它们的慢处理和死循环函数。Module可以建立树状关系。Service本身也是Module的类型。

origin集群核心配置文件在config的cluster目录下,在cluster下有子网目录,如github.com/duanhf2012/originserver的config/cluster目录下有subnet目录,表示子网名为subnet,可以新加多个子网的目录配置。子网与子网间是隔离的,后续将支持子网间通信规则,origin集群配置以子网的模式配置,在每个子网下配置多个Node服务器,子网在应对复杂的系统时可以应用到各个子系统,方便每个子系统的隔离。在示例的subnet目录中有cluster.json与service.json配置:

cluster.json如下:

{"NodeList":[{"NodeId": 1,"ListenAddr":"127.0.0.1:8001","NodeName": "Node_Test1","remark":"//以_打头的,表示只在本机进程,不对整个子网开发","ServiceList": ["TestService1","TestService2","TestServiceCall","GateService","_TcpService","HttpService","WSService"]},{"NodeId": 2,"ListenAddr":"127.0.0.1:8002","NodeName": "Node_Test1","remark":"//以_打头的,表示只在本机进程,不对整个子网开发","ServiceList": ["TestService1","TestService2","TestServiceCall","GateService","TcpService","HttpService","WSService"]}]

以上配置了两个结点服务器程序:

  • NodeId: 表示origin程序的结点Id标识,不允许重复。
  • ListenAddr:Rpc通信服务的监听地址
  • NodeName:结点名称
  • remark:备注,可选项
  • ServiceList:该Node将安装的服务列表

在启动程序命令program start nodeid=1中nodeid就是根据该配置装载服务。
service.json如下:

{"Service":{"HttpService":{"ListenAddr":"0.0.0.0:9402","ReadTimeout":10000,"WriteTimeout":10000,"ProcessTimeout":10000,"CAFile":[{"Certfile":"","Keyfile":""}]},"TcpService":{"ListenAddr":"0.0.0.0:9030","MaxConnNum":3000,"PendingWriteNum":10000,"LittleEndian":false,"MinMsgLen":4,"MaxMsgLen":65535},"WSService":{"ListenAddr":"0.0.0.0:9031","MaxConnNum":3000,"PendingWriteNum":10000,"MaxMsgLen":65535}  },"NodeService":[{"NodeId":1,"TcpService":{"ListenAddr":"0.0.0.0:9830","MaxConnNum":3000,"PendingWriteNum":10000,"LittleEndian":false,"MinMsgLen":4,"MaxMsgLen":65535},"WSService":{"ListenAddr":"0.0.0.0:9031","MaxConnNum":3000,"PendingWriteNum":10000,"MaxMsgLen":65535}  },{"NodeId":2,"TcpService":{"ListenAddr":"0.0.0.0:9030","MaxConnNum":3000,"PendingWriteNum":10000,"LittleEndian":false,"MinMsgLen":4,"MaxMsgLen":65535},"WSService":{"ListenAddr":"0.0.0.0:9031","MaxConnNum":3000,"PendingWriteNum":10000,"MaxMsgLen":65535}  }]}

以上配置分为两个部分:Service与NodeService,NodeService中配置的对应结点中服务的配置,如果启动程序中根据nodeid查找该域的对应的服务,如果找不到时,从Service公共部分查找。

HttpService配置

  • ListenAddr:Http监听地址
  • ReadTimeout:读网络超时毫秒
  • WriteTimeout:写网络超时毫秒
  • ProcessTimeout: 处理超时毫秒
  • CAFile: 证书文件,如果您的服务器通过web服务器代理配置https可以忽略该配置

TcpService配置

  • ListenAddr: 监听地址
  • MaxConnNum: 允许最大连接数
  • PendingWriteNum:发送网络队列最大数量
  • LittleEndian:是否小端
  • MinMsgLen:包最小长度
  • MaxMsgLen:包最大长度

WSService配置

  • ListenAddr: 监听地址
  • MaxConnNum: 允许最大连接数
  • PendingWriteNum:发送网络队列最大数量
  • MaxMsgLen:包最大长度

第一章:origin基础:

查看github.com/duanhf2012/originserver中的simple_service中新建两个服务,分别是TestService1.go与CTestService2.go。

simple_service/TestService1.go如下:

package simple_serviceimport ("github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service"
)//模块加载时自动安装TestService1服务
func init(){node.Setup(&TestService1{})
}//新建自定义服务TestService1
type TestService1 struct {//所有的自定义服务必需加入service.Service基服务//那么该自定义服务将有各种功能特性//例如: Rpc,事件驱动,定时器等service.Service
}//服务初始化函数,在安装服务时,服务将自动调用OnInit函数
func (slf *TestService1) OnInit() error {return nil
}

simple_service/TestService2.go如下:

import ("github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service"
)func init(){node.Setup(&TestService2{})
}type TestService2 struct {service.Service
}func (slf *TestService2) OnInit() error {return nil
}
  • main.go运行代码
package mainimport ("github.com/duanhf2012/origin/node"//导入simple_service模块_"orginserver/simple_service"
)func main(){node.Start()
}
  • config/cluster/subnet/cluster.json如下:
{"NodeList":[{"NodeId": 1,"ListenAddr":"127.0.0.1:8001","NodeName": "Node_Test1","remark":"//以_打头的,表示只在本机进程,不对整个子网开发","ServiceList": ["TestService1","TestService2"]}]
}

编译后运行结果如下:

#originserver start nodeid=1
TestService1 OnInit.
TestService2 OnInit.

第二章:Service中常用功能:

定时器:

在开发中最常用的功能有定时任务,origin提供两种定时方式:

一种AfterFunc函数,可以间隔一定时间触发回调,参照simple_service/TestService2.go,实现如下:

func (slf *TestService2) OnInit() error {fmt.Printf("TestService2 OnInit.\n")slf.AfterFunc(time.Second*1,slf.OnSecondTick)return nil
}func (slf *TestService2) OnSecondTick(){fmt.Printf("tick.\n")slf.AfterFunc(time.Second*1,slf.OnSecondTick)
}

此时日志可以看到每隔1秒钟会print一次"tick.",如果下次还需要触发,需要重新设置定时器

另一种方式是类似Linux系统的crontab命令,使用如下:


func (slf *TestService2) OnInit() error {fmt.Printf("TestService2 OnInit.\n")//crontab模式定时触发//NewCronExpr的参数分别代表:Seconds Minutes Hours DayOfMonth Month DayOfWeek//以下为每换分钟时触发cron,_:=timer.NewCronExpr("0 * * * * *")slf.CronFunc(cron,slf.OnCron)return nil
}func (slf *TestService2) OnCron(){fmt.Printf(":A minute passed!\n")
}

以上运行结果每换分钟时打印:A minute passed!

打开多协程模式:

在origin引擎设计中,所有的服务是单协程模式,这样在编写逻辑代码时,不用考虑线程安全问题。极大的减少开发难度,但某些开发场景下不用考虑这个问题,而且需要并发执行的情况,比如,某服务只处理数据库操作控制,而数据库处理中发生阻塞等待的问题,因为一个协程,该服务接受的数据库操作只能是一个
一个的排队处理,效率过低。于是可以打开此模式指定处理协程数,代码如下:

func (slf *TestService1) OnInit() error {fmt.Printf("TestService1 OnInit.\n")//打开多线程处理模式,10个协程并发处理slf.SetGoRouterNum(10)return nil
}

为了

性能监控功能:

我们在开发一个大型的系统时,经常由于一些代码质量的原因,产生处理过慢或者死循环的产生,该功能可以被监测到。使用方法如下:

func (slf *TestService1) OnInit() error {fmt.Printf("TestService1 OnInit.\n")//打开性能分析工具slf.OpenProfiler()//监控超过1秒的慢处理slf.GetProfiler().SetOverTime(time.Second*1)//监控超过10秒的超慢处理,您可以用它来定位是否存在死循环//比如以下设置10秒,我的应用中是不会发生超过10秒的一次函数调用//所以设置为10秒。slf.GetProfiler().SetMaxOverTime(time.Second*10)slf.AfterFunc(time.Second*2,slf.Loop)//打开多线程处理模式,10个协程并发处理//slf.SetGoRouterNum(10)return nil
}func (slf *TestService1) Loop(){for {time.Sleep(time.Second*1)}
}func main(){//打开性能分析报告功能,并设置10秒汇报一次node.OpenProfilerReport(time.Second*10)node.Start()
}

上面通过GetProfiler().SetOverTime与slf.GetProfiler().SetMaxOverTimer设置监控时间
并在main.go中,打开了性能报告器,以每10秒汇报一次,因为上面的例子中,定时器是有死循环,所以可以得到以下报告:

2020/04/22 17:53:30 profiler.go:179: [release] Profiler report tag TestService1:
process count 0,take time 0 Milliseconds,average 0 Milliseconds/per.
too slow process:Timer_orginserver/simple_service.(*TestService1).Loop-fm is take 38003 Milliseconds
直接帮助找到TestService1服务中的Loop函数

第三章:Module使用:

Module创建与销毁:

可以认为Service就是一种Module,它有Module所有的功能。在示例代码中可以参考originserver/simple_module/TestService3.go。

package simple_moduleimport ("fmt""github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service"
)func init(){node.Setup(&TestService3{})
}type TestService3 struct {service.Service
}type Module1 struct {service.Module
}type Module2 struct {service.Module
}func (slf *Module1) OnInit()error{fmt.Printf("Module1 OnInit.\n")return nil
}func (slf *Module1) OnRelease(){fmt.Printf("Module1 Release.\n")
}func (slf *Module2) OnInit()error{fmt.Printf("Module2 OnInit.\n")return nil
}func (slf *Module2) OnRelease(){fmt.Printf("Module2 Release.\n")
}func (slf *TestService3) OnInit() error {//新建两个Module对象module1 := &Module1{}module2 := &Module2{}//将module1添加到服务中module1Id,_ := slf.AddModule(module1)//在module1中添加module2模块module1.AddModule(module2)fmt.Printf("module1 id is %d, module2 id is %d",module1Id,module2.GetModuleId())//释放模块module1slf.ReleaseModule(module1Id)fmt.Printf("xxxxxxxxxxx")return nil
}

在OnInit中创建了一条线型的模块关系TestService3->module1->module2,调用AddModule后会返回Module的Id,自动生成的Id从10e17开始,内部的id,您可以自己设置Id。当调用ReleaseModule释放时module1时,同样会将module2释放。会自动调用OnRelease函数,日志顺序如下:

Module1 OnInit.
Module2 OnInit.
module1 id is 100000000000000001, module2 id is 100000000000000002
Module2 Release.
Module1 Release.

在Module中同样可以使用定时器功能,请参照第二章节的定时器部分。

第四章:事件使用

事件是origin中一个重要的组成部分,可以在同一个node中的service与service或者与module之间进行事件通知。系统内置的几个服务,如:TcpService/HttpService等都是通过事件功能实现。他也是一个典型的观察者设计模型。在event中有两个类型的interface,一个是event.IEventProcessor它提供注册与卸载功能,另一个是event.IEventHandler提供消息广播等功能。

在目录simple_event/TestService4.go中

package simple_eventimport ("github.com/duanhf2012/origin/event""github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service""time"
)const (//自定义事件类型,必需从event.Sys_Event_User_Define开始//event.Sys_Event_User_Define以内给系统预留EVENT1 event.EventType =event.Sys_Event_User_Define+1
)func init(){node.Setup(&TestService4{})
}type TestService4 struct {service.Service
}func (slf *TestService4) OnInit() error {//10秒后触发广播事件slf.AfterFunc(time.Second*10,slf.TriggerEvent)return nil
}func (slf *TestService4) TriggerEvent(){//广播事件,传入event.Event对象,类型为EVENT1,Data可以自定义任何数据//这样,所有监听者都可以收到该事件slf.GetEventHandler().NotifyEvent(&event.Event{Type: EVENT1,Data: "event data.",})
}

在目录simple_event/TestService5.go中

package simple_eventimport ("fmt""github.com/duanhf2012/origin/event""github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service"
)func init(){node.Setup(&TestService5{})
}type TestService5 struct {service.Service
}type TestModule struct {service.Module
}func (slf *TestModule) OnInit() error{//在当前node中查找TestService4pService := node.GetService("TestService4")//在TestModule中,往TestService4中注册EVENT1类型事件监听pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnModuleEvent)return nil
}func (slf *TestModule) OnModuleEvent(ev *event.Event){fmt.Printf("OnModuleEvent type :%d data:%+v\n",ev.Type,ev.Data)
}//服务初始化函数,在安装服务时,服务将自动调用OnInit函数
func (slf *TestService5) OnInit() error {//通过服务名获取服务对象pService := node.GetService("TestService4")在TestModule中,往TestService4中注册EVENT1类型事件监听pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnServiceEvent)slf.AddModule(&TestModule{})return nil
}func (slf *TestService5) OnServiceEvent(ev *event.Event){fmt.Printf("OnServiceEvent type :%d data:%+v\n",ev.Type,ev.Data)
}

程序运行10秒后,调用slf.TriggerEvent函数广播事件,于是在TestService5中会收到

OnServiceEvent type :1001 data:event data.
OnModuleEvent type :1001 data:event data.

在上面的TestModule中监听的事情,当这个Module被Release时监听会自动卸载。

第五章:RPC使用

RPC是service与service间通信的重要方式,它允许跨进程node互相访问,当然也可以指定nodeid进行调用。如下示例:

simple_rpc/TestService6.go文件如下:

package simple_rpcimport ("github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service"
)func init(){node.Setup(&TestService6{})
}type TestService6 struct {service.Service
}func (slf *TestService6) OnInit() error {return nil
}type InputData struct {A intB int
}func (slf *TestService6) RPC_Sum(input *InputData,output *int) error{*output = input.A+input.Breturn nil
}

simple_rpc/TestService7.go文件如下:

package simple_rpcimport ("fmt""github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service""time"
)func init(){node.Setup(&TestService7{})
}type TestService7 struct {service.Service
}func (slf *TestService7) OnInit() error {slf.AfterFunc(time.Second*2,slf.CallTest)slf.AfterFunc(time.Second*2,slf.AsyncCallTest)slf.AfterFunc(time.Second*2,slf.GoTest)return nil
}func (slf *TestService7) CallTest(){var input InputDatainput.A = 300input.B = 600var output int//同步调用其他服务的rpc,input为传入的rpc,output为输出参数err := slf.Call("TestService6.RPC_Sum",&input,&output)if err != nil {fmt.Printf("Call error :%+v\n",err)}else{fmt.Printf("Call output %d\n",output)}
}func (slf *TestService7) AsyncCallTest(){var input InputDatainput.A = 300input.B = 600/*slf.AsyncCallNode(1,"TestService6.RPC_Sum",&input,func(output *int,err error){})*///异步调用,在数据返回时,会回调传入函数//注意函数的第一个参数一定是RPC_Sum函数的第二个参数,err error为RPC_Sum返回值slf.AsyncCall("TestService6.RPC_Sum",&input,func(output *int,err error){if err != nil {fmt.Printf("AsyncCall error :%+v\n",err)}else{fmt.Printf("AsyncCall output %d\n",*output)}})
}func (slf *TestService7) GoTest(){var input InputDatainput.A = 300input.B = 600//在某些应用场景下不需要数据返回可以使用Go,它是不阻塞的,只需要填入输入参数err := slf.Go("TestService6.RPC_Sum",&input)if err != nil {fmt.Printf("Go error :%+v\n",err)}//以下是广播方式,如果在同一个子网中有多个同名的服务名,CastGo将会广播给所有的node//slf.CastGo("TestService6.RPC_Sum",&input)
}

您可以把TestService6配置到其他的Node中,比如NodeId为2中。只要在一个子网,origin引擎可以无差别调用。开发者只需要关注Service关系。同样它也是您服务器架构设计的核心需要思考的部分。

第六章:HttpService使用

HttpService是origin引擎中系统实现的http服务,http接口中常用的GET,POST以及url路由处理。

simple_http/TestHttpService.go文件如下:

package simple_httpimport ("fmt""github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service""github.com/duanhf2012/origin/sysservice""net/http"
)func init(){node.Setup(&sysservice.HttpService{})node.Setup(&TestHttpService{})
}//新建自定义服务TestService1
type TestHttpService struct {service.Service
}func (slf *TestHttpService) OnInit() error {//获取系统httpservice服务httpervice := node.GetService("HttpService").(*sysservice.HttpService)//新建并设置路由对象httpRouter := sysservice.NewHttpHttpRouter()httpervice.SetHttpRouter(httpRouter,slf.GetEventHandler())//GET方法,请求url:http://127.0.0.1:9402/get/query?nickname=boyce//并header中新增key为uid,value为1000的头,则用postman测试返回结果为://head uid:1000, nickname:boycehttpRouter.GET("/get/query", slf.HttpGet)//POST方法 请求url:http://127.0.0.1:9402/post/query//返回结果为:{"msg":"hello world"}httpRouter.POST("/post/query", slf.HttpPost)//GET方式获取目录下的资源,http://127.0.0.1:port/img/head/a.jpghttpRouter.SetServeFile(sysservice.METHOD_GET,"/img/head/","d:/img")return nil
}func (slf *TestHttpService) HttpGet(session *sysservice.HttpSession){//从头中获取key为uid对应的值uid := session.GetHeader("uid")//从url参数中获取key为nickname对应的值nickname,_ := session.Query("nickname")//向body部分写入数据session.Write([]byte(fmt.Sprintf("head uid:%s, nickname:%s",uid,nickname)))//写入http状态session.WriteStatusCode(http.StatusOK)//完成返回session.Done()
}type HttpRespone struct {Msg string `json:"msg"`
}func (slf *TestHttpService) HttpPost(session *sysservice.HttpSession){//也可以采用直接返回数据对象方式,如下:session.WriteJsonDone(http.StatusOK,&HttpRespone{Msg: "hello world"})
}

注意,要在main.go中加入import _ “orginserver/simple_service”,并且在config/cluster/subnet/cluster.json中的ServiceList加入服务。

第七章:TcpService服务使用

TcpService是origin引擎中系统实现的Tcp服务,可以支持自定义消息格式处理器。只要重新实现network.Processor接口。目前内置已经实现最常用的protobuf处理器。

simple_tcp/TestTcpService.go文件如下:

package simple_tcpimport ("fmt""github.com/duanhf2012/origin/network/processor""github.com/duanhf2012/origin/node""github.com/duanhf2012/origin/service""github.com/duanhf2012/origin/sysservice""github.com/golang/protobuf/proto""orginserver/simple_tcp/msgpb"
)func init(){node.Setup(&sysservice.TcpService{})node.Setup(&TestTcpService{})
}//新建自定义服务TestService1
type TestTcpService struct {service.Serviceprocessor *processor.PBProcessortcpService *sysservice.TcpService
}func (slf *TestTcpService) OnInit() error {//获取安装好了的TcpService对象slf.tcpService =  node.GetService("TcpService").(*sysservice.TcpService)//新建内置的protobuf处理器,您也可以自定义路由器,比如json,后续会补充slf.processor = processor.NewPBProcessor()//注册监听客户连接断开事件slf.processor.RegisterDisConnected(slf.OnDisconnected)//注册监听客户连接事件slf.processor.RegisterConnected(slf.OnConnected)//注册监听消息类型MsgType_MsgReq,并注册回调slf.processor.Register(uint16(msgpb.MsgType_MsgReq),&msgpb.Req{},slf.OnRequest)//将protobuf消息处理器设置到TcpService服务中slf.tcpService.SetProcessor(slf.processor,slf.GetEventHandler())return nil
}func (slf *TestTcpService) OnConnected(clientid uint64){fmt.Printf("client id %d connected\n",clientid)
}func (slf *TestTcpService) OnDisconnected(clientid uint64){fmt.Printf("client id %d disconnected\n",clientid)
}func (slf *TestTcpService) OnRequest (clientid uint64,msg proto.Message){//解析客户端发过来的数据pReq := msg.(*msgpb.Req)//发送数据给客户端err := slf.tcpService.SendMsg(clientid,&msgpb.Req{Msg: proto.String(pReq.GetMsg()),})if err != nil {fmt.Printf("send msg is fail %+v!",err)}
}

第八章:其他系统模块介绍

  • sysservice/wsservice.go:支持了WebSocket协议,使用方法与TcpService类似
  • sysmodule/DBModule.go:对mysql数据库操作
  • sysmodule/RedisModule.go:对Redis数据进行操作
  • sysmodule/HttpClientPoolModule.go:Http客户端请求封装
  • log/log.go:日志的封装,可以使用它构建对象记录业务文件日志
  • util:在该目录下,有常用的uuid,hash,md5,协程封装等工具库
  • https://github.com/duanhf2012/originservice: 其他扩展支持的服务可以在该工程上看到,目前支持firebase推送的封装。

origin游戏服务器引擎相关推荐

  1. Scut游戏服务器引擎6.1.5.6发布,直接可运行,支持热更新

    1. 增加exe版(console),web版本(IIS)的游戏服宿主程序 2. 增加Model支持脚本化,实现不停服更新 3. 增加Language支持脚本化 4. 修改Sns与Pay Center ...

  2. Wind分布式游戏服务器引擎的实现

    Wind Wind是一款面向云的高性能.高效率以及高扩展性的大型分布式游戏服务器引擎.Wind利用Python语言的简洁语法以及丰富的生态库来提高游戏业务的开发效率,针对一些对性能有要求的游戏业务功能 ...

  3. Wind:一款面向云的分布式游戏服务器引擎

    Wind是一款面向云的高性能.高效率以及高扩展性的大型分布式游戏服务器引擎.Wind利用Python语言的简洁语法以及丰富的生态库来提高游戏业务的开发效率,针对一些对性能有要求的游戏业务功能(如实时战 ...

  4. 类Photon游戏服务器引擎Matchvs简介

    在介绍Matchvs前,先来了解下是什么游戏服务器引擎?虽然很多人可能都听过国外的Photon,但相对于引擎,大家对游戏服务器框架这个概念可能更为熟悉.框架其实就是针对后台通讯部分搭建一个可复用的设计 ...

  5. Egret与国内首个商业化游戏服务器引擎Matchvs达成深度合作

    日前,Matchvs与白鹭引擎(Egret)正式达成合作.双方在市场.产品和服务等方面达成共识,共同锁定H5游戏领域,发布前后端一体解决方案.在此次合作中,Matchvs为白鹭引擎提供后端联网解决方案 ...

  6. 利用游戏服务器引擎Matchvs开发联网微信小游戏

    Matchvs是一款十分易用的游戏服务器引擎,开发者通过SaaS层提供的API,即可完成"就近"节点接入.玩家匹配.游戏数据通信的建立:PaaS提供GS开发框架.托管平台,无需自有 ...

  7. 游戏服务器引擎Matchvs游戏云第三方绑定教程

    众所周知,Matchvs是国内一款专注于移动游戏的游戏服务器引擎.开发者通过接入Matchvs的SDK,即便没有服务器开发人员,也可以轻松完成联网游戏的开发.近期,Matchvs开放了第三方绑定功能, ...

  8. python游戏服务器框架_有那些比较成熟的开源游戏服务器引擎/框架(编程语言不限)?...

    更新,没有看到服务器(逃. 下面仅为游戏引擎和框架推荐,需要的小伙伴简单看一下,正确的答案努力撰写中. 从角色扮演游戏到即时策略游戏,从冒险解谜游戏到动作射击游戏,甚至是只有一兆大小的迷你游戏,都有起 ...

  9. 游戏服务器引擎的设计(一)介绍游戏服务器部署框架

    服务器的架构,根据游戏类型不同大多有:账号服务器.全局服务器.网关服务器.场景服务器.中心服务器.存储服务器,配合其他的服务器(比如日志服,监控服等).传统的游戏是单服模式,现在也有很多的是分布式模式 ...

  10. 游戏服务器引擎的设计(二)开发游戏服务器底层 及libuv使用

    服务器底层,个人任务认为稳定.高效.易用最重要.如果非要排个序的话 稳定 > 易用 > 高效. 我是用的libuv这个库作为基础支持库的.为啥用它,主要是网络库不想自己写了,有现成的最好. ...

最新文章

  1. ARP协议详解之ARP动态与静态条目的生命周期
  2. centos7 开机后进去了命令行_Linux系统管理:开机启动流程(二)
  3. 文件的读操作 c# 1614526130
  4. 3-JAVA中的JSON操作
  5. 多目标粒子群算法_PSO粒子群算法可视化
  6. es6基本语法,vue基本语法
  7. 住170平以上的大平层大户型什么感觉?
  8. hbase 源代码解析(2)HAdmin 的表创建过程
  9. 关于qt使用sqlist数据库的注意事项
  10. Algorithm:数学建模大赛(CUMCM/NPMCM)之05B《DVD在线租赁》
  11. BERT模型深度解析
  12. PythonR LEfSe 分析
  13. 程序化交易逆境中的奋斗史!
  14. Photoshop分享| 拼贴海报
  15. 【SpringBoot-3】Lombok使用详解
  16. java号码分身_电话号码分身问题
  17. php kingcms 模型调用,KingCMS 中模板、模块、模型区别
  18. 信噪比、添加高斯白噪声
  19. 2008系统服务器日志在哪里,windows-server-2008 – 如何将Windows Server 2008事件日志发送到syslog服务器?...
  20. UWB室内定位系统铸造智能化企业安全管理系统

热门文章

  1. 社工手段日益精进,MacOS和IOS系统还安全吗?
  2. txt转excel的工具
  3. VC++ MFC 学习资料
  4. yacc语法分析minipascal_用Yacc实现语法分析器-4-编译原理
  5. netframework2.0安装
  6. VsCode 中 vue代码格式化 (整理代码)
  7. Abaqus运行fortan报错:“Error in job Job-1: Problem during compilation - D:\test.for”
  8. JavaSE详细教程.1
  9. 米侠浏览器如何添加脚本 米侠浏览器中添加脚本的具体操作步骤
  10. 基于变分模态分解与麻雀优化最小二乘支持向量机的短期电力负荷预测(VMD-SSA-LSSVM)