在as3中使用protobuf
在最近参与开发的adobe air项目中,前后端的通信协议从XML、JSON再到protobuf,最后选择protobuf原因,主要是前后端维护protobuf协议就行了,同时还可以利用IDE做一些编译检查。目前我能找到的protobuf as3开源库,都存在一些问题:不支持嵌套类,生成代码无法编译等等。于是花了一点时间,参考google protobuf相关说明,编写protobuf-as3以及protoc-as3,用于支持运行时及代码生成,https://github.com/zhongfq/protobuf-as3。
protobuf-as3库只支持proto3格式,proto3列出的数据类型基本都支持。
以下proto文件将生成5个as3类:Token.as、Token$Type.as、TokenBindingResponseCode.as、TokenBindingRequest.as、TokenBindingResponse.as。我们以‘$’作为分隔符以实现protobuf类的嵌套。
syntax = "proto3";
package user.token; message Token {
enum Type {
NONE = ;
QQ = ;
WEIBO = ;
WECHAT = ;
} Type type = ;
string value = ;
} enum TokenBindingResponseCode {
ERROR = ;
OK = ;
EXIST = ;
} message TokenBindingRequest {
Token token = ;
} message TokenBindingResponse {
TokenBindingResponseCode responseCode = ;
Token token = ;
}
var token:Token = new Token();
token.type = Token$Type.QQ;
token.value = "xxxxxx"; var req:TokenBindingRequest = new TokenBindingRequest();
req.token = token;
protobuf数据不包含任何的元数据,所以对于一段数据而言,你是不能够区别这段数据是属于哪一条协议的,因此对于前后端的交互,我引入12字节的头部(length、session、type)。
package network {
import flash.utils.ByteArray;
internal class Packet {
private var _session:int;
private var _type:int;
private var _data:ByteArray;
public function Packet(session:int, type:int, data:ByteArray) {
_session = session;
_type = type;
_data = data;
_data.position = 0;
}
public function get session():int {
return _session;
}
public function get type():int {
return _type;
}
public function get data():ByteArray {
return _data;
}
}
}
package network {
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.Endian;
internal class PacketBuffer {
//length + session + type
private static const HEADER_LENGTH:int = 12;
private var _length:int = 0;
private var _position:int = 0;
private var _packet:Packet = null;
public function PacketBuffer() {
}
public function pack(socket:Socket):Packet {
// 消息长度至少为12, length + session + type
if (socket.bytesAvailable <= 0 || (_length == 0 && socket.bytesAvailable < HEADER_LENGTH)) {
return null;
}
socket.endian = Endian.BIG_ENDIAN;
if (_length == 0) {
_length = socket.readInt();
// valid packet: length + session + type >= 12
if (_length < HEADER_LENGTH) {
socket.close();
return null;
}
var session:int = socket.readInt();
var type:int = socket.readInt();
_position = 0;
_packet = new Packet(session, type, new ByteArray());
}
if (socket.bytesAvailable > 0 || _length == HEADER_LENGTH) {
var len:int = Math.min(_length - HEADER_LENGTH - _position, socket.bytesAvailable);
socket.readBytes(_packet.data, _position, len);
_position += len;
if (_position == _length - HEADER_LENGTH) {
var ret:Packet = _packet;
_packet = null;
_position = 0;
_length = 0;
return ret;
}
}
return null;
}
}
}
syntax = "proto3";
enum CommandCode {
// gateway
GATEWAY = 0x0000;
// login
SIGN_IN = 0x0100;
CHECK_ACCOUNT = 0x0101;
SIGN_UP = 0x0102;
QUICK_ENROLL = 0x0103;
// user
USER_MODIFIER = 0x0200;
TOKEN_BINDING = 0x0201;
USER_STAT = 0x0202;
USER_AVATAR = 0x0203;
}
CommandCode作为数据包的类型标识,用于上面所说头部中的类型段。
对于发送一个数据包,方式如下:
private function sendPacket(packet:Packet):void {
// length + session + type
_socket.endian = Endian.BIG_ENDIAN;
_socket.writeInt(packet.data.length + 12);
_socket.writeInt(packet.session);
_socket.writeInt(packet.type);
_socket.writeBytes(packet.data);
_socket.flush();
}
对于接收数据包,方式如下:
private function socketDataHandler(event:ProgressEvent):void {
var packet:Packet;
while ((packet = _packetBuffer.pack(_socket)) != null) {
dispatchPacket(packet);
}
}
session变量由服务器维护,服务器每发送一条用户数据,session就+1,前端断线重连时,发送session与服务作对比,如果一样,就是执行断线重连,如果不一样就强制走登录流程。
在as3中使用protobuf的更多相关文章
- 在Wcf中应用ProtoBuf替代默认的序列化器
Google的ProtoBuf序列化器性能的牛逼已经有目共睹了,可以把它应用到Socket通讯,队列,Wcf中,身为dotnet程序员一边期待着不久后Grpc对dotnet core的支持更期待着Wc ...
- webapi 中使用 protobuf
相比json来说,好处是速度更快,带宽占用更小.其效果大致等于json+Gzip. 在webapi中使用protobuf的方法为: 引用nuget包 Install-Package protobuf- ...
- as3中的多线程
从fp11.4开始支持worker技术, 即as3中的线程概念, 到了fp11.5, flascc中开始支持pthread家族来创建线程. 总的来说, as3中有两种创建线程的方法: 1.直接在as3 ...
- 在网络通讯中应用Protobuf
在网络通讯中应用Protobuf Protobuf的设计非常适用于在网络通讯中的数据载体,它序列化出来的数据量少再加上以K-V的方式来存储数据,对消息的版本兼容性非常强:还有一个比较大的优点就是有着很 ...
- AS3中释放优化的几条常识
as3中垃圾和堆弃物如不及时清理,会造成进程的速度方面授予限制,下面讲几点关于释放优化的几条内容. 被删除对象在外部的所有引用一定要被删除干净才能被系统当成垃圾回收处理掉: 父对象内部的子对象被外部其 ...
- 怎样在Spark、Flink应用中使用Protobuf 3的包
如果在在Spark.Flink应用中使用Protobuf 3的包,因为Spark默认使用的是2.5版本的包,提交任务时,可能会报如下异常: com.google.protobuf.CodedInput ...
- AS3中的单件(Singleton)模式
单件(singleton)模式在c#中是最容易实现的模式,其主要用意就在于限制使用者用new来创建多个实例.但在as3中,构造函数必须是public的(语法本身要求的),而且也不能在构造函数中抛出异常 ...
- AS3中的getChildByName
[转载的...............] 在AS3中,我们可以用getChildByName来获取一个元件,但是要注意返回的类型是DisplayObject,这样一旦我们的元件中有一些自定义的方法就不 ...
- 在lua环境中使用protobuf
最近在cocos2dx的项目中,需要在LUA脚本层使用protobuf协议.官方已经推出了很多种语言的版本.但唯独LUA版本不全.于是开始研究protobuf在LUA下的实现,将完整的过程记录了下来, ...
随机推荐
- AngularJs的UI组件ui-Bootstrap分享(十四)——Carousel
Carousel指令是用于图片轮播的控件,引入ngTouch模块后可以在移动端使用滑动的方式使用轮播控件. <!DOCTYPE html> <html ng-app="ui ...
- linux下删除文件夹的命令
使用rm -rf 目录名字 命令即可 -r 就是向下递归,不管有多少级目录,一并删除-f 就是直接强行删除,不作任何提示的意思 eg 删除文件夹实例:rm -rf /var/log/httpd/acc ...
- auto_ptr源码剖析
/* * Copyright (c) 1997-1999 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, ...
- impress.js webslide 参数
data-transition-duration="2000" 改变切换场景的速度,默认1000data-perspective="500" 改变透视的深度,默 ...
- php 序列化、json
序列化 和 反序列化1. serialize和unserialize函数 2. json_encode 和 json_decode 使用JSON格式序列化和反序列化3. var_export 和 ev ...
- Spark源码学习1.6——Executor.scala
Executor.scala 一.Executor类 首先判断本地性,获取slaves的host name(不是IP或者host: port),匹配运行环境为集群或者本地.如果不是本地执行,需要启动一 ...
- Java和eclipse常用操作
eclipse: ctrl+F10 显示行号 ctrl+shift+F 自动对齐 ctrl+/ 注释 java: jar包: Manifest-Version - 指定清单文件的版本号 Main-Cl ...
- LayaAir引擎——(七)
LayaAir引擎——人物控制TiledMap地图移动和墙壁检测 所需要的软件: LayaAir IDE 1.0.2版本 TiledMap 所需要的东西: 地图:53 * 32,(48*48) 人物: ...
- XML代码生成器——XMLFACTORY 简介(二)
XML代码生成器——XMLFACTORY 简介(二) 因为春节和项目上线的原因,离写上一篇文章的时间已经好久了. 不知道是事情太多了,还是自已效率太低了.总之是时间不够用. 哎,苦逼的程序员 ...
- IOS 更改百度地图的定位图片
使用了百度地图的SDK,定位图片一直是蓝色的小圆点,很不喜欢,想换成自定义的图片,在网上搜罗了一大通,找到了解决的方案. 写下如下代码: //定位图层自定义样式参数 BMKLocationViewDi ...