protobuf 是传输数据序列化的一个通用规则,相比xml和json更快更小。
本次使用的是proto3,3相比于2有一些特性上的不同,例如3默认了optional声明。
所有字段都是可选赋值,这样做是为了兼容有些字段会在特定版本被废弃,序列化时,没有的字段不会被转化。
caretor js 使用
编写好proto文件,就可以使用protoc进行编译了,creatorjs引用google-protobuf.js的时候会有问题,解决无果以后我决定使用protobufjs,使用protobufjs最好有npm环境来下载安装,nodejs和npm的安装这里就不多介绍了。
- 安装protobufjs
-g 是全局安装,安装完以后,找到目录,配置好…/protobufjs/bin 环境变量,bin目录下有两个可执行文件 pbjs和pbts,是用来编译proto文件的。使用protobufjs就不会用到protoc。
# npm install -g protobufjs
- 编译proto文件
// game.proto
syntax = "proto3"
message Login {
string username = 1;
string password = 2;
int32 uid = 3;
}
message LoginResult {
string token = 1;
}
配置好环境变量,就使用pbjs编译proto文件
# pbjs -t json-module game.proto > client.json
# pbjs -t static-module game.proto > clientProto.js
-t [params] | 参数说明 |
---|---|
json | JSON representation |
json-module | JSON representation as a module |
proto2 | Protocol Buffers, Version 2 |
proto3 | Protocol Buffers, Version 3 |
static | Static code without reflection (non-functional on its own) |
static-module | Static code without reflection as a module |
注意:不同参数导出的的文件类型不一样。
- js中使用
// proto.js
const proto = require("clientProto")
module.exports = {
// static-module
proto: function(name, pwd) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readystatus = 4 && xhr.status >= 200 && xhr.status < 300) {
var b = stringToBytes(xhr.responseText); //这里需要将字符串转为byte数组
proto.LoginResult.decode(b);
}
}
xhr.open("POST", "localhost:8080/login");
m_xhr.setRequestHeader("Content-Type","application/x-protobuf");
m_xhr.setRequestHeader("Accept","application/x-protobuf");
if (m_xhr.overrideMimeType){
//这个是必须的,否则返回的是字符串,导致protobuf解码错误
//具体见http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html
m_xhr.overrideMimeType("text/plain; charset=x-user-defined");
}
var param = proto.Login.encode({username:name, password:pwd).finish();
xhr.send(param);
},
// json-module, json文件没使用,用过后补全
proto2: function() {
}
};
golang 使用
go使用的话,我用的是iris框架,这里就举例iris怎么解析。
package main
import (
"gameProto"
"github.com/golang/protobuf/proto"
"github.com/kataras/iris"
)
func main() {
app := iris.New()
app.Post("/login", loginHandler)
app.Run(iris.Addr("0.0.0.0:8080"))
}
func ProtoUnmashal(data []byte, v interface{}) error {
return proto.Unmashal(data, v.(proto.Message)) // proto解析方法
}
func loginHandler(c iris.Context) {
login := &gameProto.Login{} // 这个是解析后go结构
// 解析客户端传的参数
if c.UnmarshalBody(login, iris.UnmarshalerFunc(ProtoUnmashal)); err != nil {
return
}
// do something ...
loginResult := &gameProto.LoginResult{}
loginResult.Token = "zx7g9f8h79j80sh98af766"
if b, err := proto.Mashal(loginResult); err != nil {
return
} else {
c.Write(b)
}
}