内容简介:将 Hello 消息路由到 game 模块中。打开 LeafServerExample gate/router.go,敲入如下代码:在 game 模块中处理 Hello 消息了。打开 LeafServerExample game/internal/handler.go,敲入如下代码:获取protobufjs,在LeafServerCocosClient目录下:
项目目的:
- 开发一个交互性的小游戏,限于服务端经验较少,故开始学习leaf框架,客户端用cocos creator。
- 网络上此类可学习案例较少,故想一边学习,一边分享给后学者,谨以此勉励自己!
环境搭建:
-
golang 环境搭建和cocos creator的环境搭建网上教程很多,不再赘述,golang IDE可使用Goland。
-
leaf框架地址: https://github.com/name5566/leaf.git
-
leaf入门教程: https://github.com/name5566/leaf/blob/master/TUTORIAL_ZH.md
-
example gihub地址:
-
LeafServerExample搭建:
获取:
git clone https://github.com/ddkgo/LeafServerExample.git
设置 LeafServerExample目录到 GOPATH 环境变量后获取 Leaf:
go get github.com/name5566/leaf
获取protobuf支持:
go get github.com/golang/protobuf/proto
正文:
server接收和处理消息:
1.创建一个msgPro.proto:
syntax = "proto3"; package msg; message Hello { int32 id = 1; string name = 2; }
编译 msgPro.proto 文件(对此不了解?请先阅读《 在 Golang 中使用 Protobuf 》一文)得到 msgPro.pb.go 文件,命令如下:
protoc --go_out=. msgPro.proto
将msgPro.pb.go 放在LeafServerExample src/msg文件夹下。
2.编辑 msg.go 文件:
package msg import ( "github.com/name5566/leaf/network/protobuf" ) // 使用 Protobuf 消息处理器 var Processor = protobuf.NewProcessor() func init() { Processor.Register(&Hello{}) }
3.接下来处理 Hello 消息的路由:
将 Hello 消息路由到 game 模块中。打开 LeafServerExample gate/router.go,敲入如下代码:
package gate import ( "server/msg" "server/game" ) func init() { // 这里指定消息 Hello 路由到 game 模块 msg.Processor.SetRouter(&msg.Hello{}, game.ChanRPC) }
4.处理消息:
在 game 模块中处理 Hello 消息了。打开 LeafServerExample game/internal/handler.go,敲入如下代码:
package internal import ( "server/msg" "reflect" "github.com/name5566/leaf/gate" "github.com/name5566/leaf/log" "github.com/golang/protobuf/proto" ) func init() { // 向当前模块(game 模块)注册 Hello 消息的消息处理函数 handleHello handler(&msg.Hello{}, handleHello) } func handler(m interface{}, h interface{}) { skeleton.RegisterChanRPC(reflect.TypeOf(m), h) } func handleHello(args []interface{}) { // 收到的 Hello 消息 m := args[0].(*msg.Hello) // 消息的发送者 a := args[1].(gate.Agent) // 输出收到的消息的内容 log.Debug("hello %v", m.GetName()) retBuf :=&msg.Hello{ Name: *proto.String("client"), } // 给发送者回应一个 Hello 消息 a.WriteMsg(retBuf) }
client接收和处理消息:
获取protobufjs,在LeafServerCocosClient目录下:
npm install protobufjs
1.proto编译成静态文件:
把msgPro.proto 复制到LeafServerCocosClient node_modules.bin文件夹下,把proto文件编译成静态文件使用:
pbjs -t static-module -w commonjs -o protocol.js msgPro.proto pbts -o protocol.d.ts protocol.js
把protocol.js 和protocol.d.ts拷贝到LeafServerCocosClient assets\script\protocol文件夹中.
2.创建websocket并连接:
新建netControl类:
const {ccclass, property} = cc._decorator; //定义全局的变量 import * as onfire from "./libs/onfire/onfire.js"; //处理事件的类库 import {netConfig} from './NetConfig' @ccclass export class netControl extends cc.Component { private _sock:WebSocket = null //当前的webSocket的对象 connect(){ if(this._sock ==null || this._sock.readyState!==1){ //当前接口没有打开 //重新连接 this._sock = new WebSocket(netConfig.host+":"+netConfig.port) this._sock.onopen = this._onOpen.bind(this); this._sock.onclose = this._onClose.bind(this); this._sock.onmessage = this._onMessage.bind(this); } return this; } _onOpen(){ onfire.fire("onopen") } _onClose(err){ onfire.fire("onclose",err) let self = this let reVar = setInterval(function(){ // 先对重连过后的Websocket进行判断,如果重连成功则断开循环 if(self._sock.readyState == 1){ clearInterval(reVar) } self._sock = new WebSocket(netConfig.host+":"+netConfig.port) }, 5000) //每5秒尝试一次重连 } _onMessage(obj){ onfire.fire("onmessage",obj) } send(msg){ if(this._sock.readyState == 1){ this._sock.send(msg); } } protoBufAddtag(tag: number,buffer: Uint8Array){ let addtag_buffer=new Uint8Array(buffer.length+2) let tagBinary = this.binary(tag,2) addtag_buffer.set(tagBinary,0) addtag_buffer.set(buffer.subarray(0,buffer.length),2) return addtag_buffer } parseProtoBufId(obj,callback:Function){ let blob:Blob = obj.data let reader = new FileReader(); reader.readAsArrayBuffer(blob); reader.onload = function(e) { let unit16 = new Uint16Array(e.target.result) let id = unit16[0] console.log("receive message id = "+id) let dataUnit8Array = new Uint8Array(e.target.result) dataUnit8Array = dataUnit8Array.slice(2) callback(id,dataUnit8Array) } } binary (num:number, Bits:number) { let resArry = [] let xresArry = [] let i=0; for(;num>0;){ resArry.push(num % 2) num=num/2 i++; } for(let j=i-1;j>=0;j--) xresArry.push(resArry[j]) if (Bits < xresArry.length) { console.log("位数小于二进制位数") } if (Bits) { for(let r = xresArry.length; r < Bits; r++) { xresArry.unshift(0) } } //return xresArry.join().replace(/,/g, ''); return xresArry } }
由于在 Leaf 中, 默认的 Protobuf Processor 将一个完整的 Protobuf 消息定义为如下格式:
------------------------- | id | protobuf message | -------------------------
所以在发送消息时需要加上头部id:
sendHello(name : string){ let protocolId = 0 let message = msg.Hello.create({ id:0,name:name }) let buffer = msg.Hello.encode(message).finish() //leaf 前两位为协议序号,故需包装一下 let addtag_buffer = this.netControl.protoBufAddtag(protocolId,buffer) this.netControl.send(addtag_buffer); console.log("sendToWS"); }
接收到leaf返回的消息时:
onMessage(obj){ //leaf 前两位为协议序号,需要解一下啊协议序号 this.netControl.parseProtoBufId(obj,this.OnGameMessage.bind(this)) }
同样的前两位是leaf自动加上的id,需要处理下:
parseProtoBufId(obj,callback:Function){ let blob:Blob = obj.data let reader = new FileReader(); reader.readAsArrayBuffer(blob); reader.onload = function(e) { let unit16 = new Uint16Array(e.target.result) let id = unit16[0] console.log("receive message id = "+id) let dataUnit8Array = new Uint8Array(e.target.result) dataUnit8Array = dataUnit8Array.slice(2) callback(id,dataUnit8Array) } }
具体Helloworld 类:
import {netControl} from "./NetControl" import * as onfire from "./libs/onfire/onfire" import { msg } from "./protocol/protocol.js" const {ccclass, property} = cc._decorator @ccclass export default class Helloworld extends cc.Component { @property(cc.Label) label: cc.Label = null; @property text: string = 'hello'; private msssageFire private netControl:netControl = null private proto onLoad(){ this.netControl = new netControl() } start () { // init logic this.label.string = this.text; this.netControl.connect(); this.msssageFire=onfire.on("onmessage",this.onMessage.bind(this)) } OnBtnSendHello(){ this.sendHello("ddk") } sendHello(name : string){ let protocolId = 0 let message = msg.Hello.create({ id:0,name:name }) let buffer = msg.Hello.encode(message).finish() //leaf 前两位为协议序号,故需包装一下 let addtag_buffer = this.netControl.protoBufAddtag(protocolId,buffer) this.netControl.send(addtag_buffer); console.log("sendToWS"); } onMessage(obj){ //leaf 前两位为协议序号,需要解一下啊协议序号 this.netControl.parseProtoBufId(obj,this.OnGameMessage.bind(this)) } OnGameMessage(id: number,data: Uint8Array){ if(id===0){ console.log("get Hello message!"); let gameMsg = msg.Hello.decode(data) console.log(gameMsg) } } onDestroy(){ onfire.un(this.msssageFire); } }
截图:
server:
client:
goland build setting:
参考:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 十余行代码完成迁移学习,百度PaddleHub实战解读
- 【实战教程】使用知晓云完成小程序客服消息的自动回复
- 利用python完成大学刷课(从0到完成的思路)
- 如何用短信完成XSS?
- 神经网络如何完成表征?
- 完成端口服务器模型
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Node.js开发实战
[美] Jim R. Wilson / 梅晴光、杜万智、陈琳、纪清华、段鹏飞 / 华中科技大学出版社 / 2018-11-10 / 99.90元
2018年美国亚马逊书店排名第一的Node.js开发教程。 . Node.js是基于Chrome V8引擎的JavaScript运行环境,它采用事件驱动、非阻塞式I/O模型,具有轻量、高效的特点。Node.j s 工作在前端代码与 数据存储层之间,能够提高web应用的工作效率和 响应速度。本书以最新版Node.js 8为基础,从实际案例出发 讲解Node.js的核心工作原理和实用开发技......一起来看看 《Node.js开发实战》 这本书的介绍吧!