在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 = 0;
        QQ = 1;
        WEIBO = 2;
        WECHAT = 3;
    }

    Type type = 1;
    string value = 2;
}

enum TokenBindingResponseCode {
    ERROR = 0;
    OK = 200;
    EXIST = 400;
}

message TokenBindingRequest {
    Token token = 1;
}

message TokenBindingResponse {
    TokenBindingResponseCode responseCode = 1;
    Token token = 2;
}
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与服务作对比,如果一样,就是执行断线重连,如果不一样就强制走登录流程。

时间: 2024-10-30 09:13:58

在as3中使用protobuf的相关文章

在erlang项目中使用protobuf

在erlang项目中使用protobuf http://blog.csdn.net/mycwq/article/details/21864191 protobuf是google的一个序列化框架,类似XML,JSON,其特点是基于二进制,比XML表示同样一段内容要短小得多,还可以定义一些可选字段,广泛用于服务端与客户端通信.文章将着重介绍在erlang中如何使用protobuf. 首先google没有提供对erlang语言的直接支持,所以这里使用到的第三方的protobuf库(erlang_pro

cocos2d-x lua 中使用protobuf并对http进行处理

本文介绍 cocos2d-x lua 中使用http 和 基于cocos2d-x 对lua http的封装(部分ok) 本博客链接 http://blog.csdn.net/vpingchangxin/article/details/24458051 protobuf  Google的一个非常好用的数据传输的封装 说实话Google的东西确实比較好用 所以我们前后端数据交换就用他了 只是Google没有对lua进行支持 还好社区有开源的大侠们贡献 找了全部关于lua protobuf 我仅仅找到

FB AS3 中,使用条件编译,实现debug、release的代码分离编译。

问题的产生: 在项目中看到有关这样的代码,不理解,就查找了相关的资料. 在这里看懂CONFIG::release与CONFIG::dubug的用法,所以不理解. 查到网上,找到一个例子来介络,就拿来凑合用着,还是易懂的. 1. FB AS3 中,使用条件编译,效果类似:VS的#if DEBUG与#if RELEASE,相比之下,FB中的宏定义更灵活 这是一个有关的例子,具体可以参考这里:http://blog.csdn.net/linjf520/article/details/7728403.由

用Netty和Raphael来写塔防online游戏(二) - JS中使用protobuf协议

一. 简单介绍一下protobuf: Protocol Buffers are a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more, originally designed at Google . 如今,已经有人用JS实现了protobuf协议,就是ProtoBu

as3中的多线程

从fp11.4开始支持worker技术, 即as3中的线程概念, 到了fp11.5, flascc中开始支持pthread家族来创建线程. 总的来说, as3中有两种创建线程的方法: 1.直接在as3中利用worker家族接口来创建和使用线程. 2.利用flascc技术在c中使用pthread家族接口来创建和使用线程.adobe官方文档明确指出, 使用pthread创建的线程, 最终也是使用as3中的worker来实现的. 一.worker对象的创建和获取 1.利用worker家族接口创建的wo

AS3中的Dictionary类

AS3中的Dictionary类(flash.utils.Dictionary)是一个新的AS类.Dictionary类和Object唯一的区别在于:Dictionary对象可以使用非字符串作为键值对的键.例如: var obj:Object = new Object();obj["name"] = 1; // 键是字符串"name"obj[1] = 2; // 键是1 (被转换成字符串"1")obj[new Object()] = 3; //

AS3中正则表达式对反斜杠的替换

一个有趣的小问题,下面的正则表达式能替换成功么? var __str:String = \'12346789\'; trace(__str.replace(/\\/g, \'5\')); 答案是:不能.trace出来的结果为: [trace] 12346789 其实正则本身并没有写错,错在被替换的字符串.反斜杠“”在AS3中是转义符,会将其后的任何值转换为本身,因此看到的字符串其实本身就是12346789,也就是没有反斜杠,当然无法搜索到. 直接trace(__str),结果和上面的trace相

项目中使用protobuf 3.0

protocol buffer从3.0 原生的compiler支持c++,Java,Python,Go,Ruby,JavaNano,JavaScript,Objective-C,C#,PHP这篇文章作为上一篇文章的补充,简单记录下一些变化. protobuf的开源地址为:https://github.com/google/protobuf protocol compiler下载地址为:https://github.com/google/protobuf/releases 官方定义message类

ActionScript3.0(AS3)中的泛型数组Vector

Adobe官方并没有"泛型数组"的叫法,这是我自己对Vector的叫法(有点标题党),不过Vector在使用上确实跟c#中的泛型数组有些相似之处. 原作者:菩提树下的杨过出处:http://yjmyzz.cnblogs.com 我们知道:ActionScript3.0中的Array数组可以存放多种类型,甚至在同一个Array数组中,可以同时存入String,Object,Number...,但其实我们在实际开发中,通常一个数组中所保存的元素类型都是一致的,为了改进这种情况下的效率,AS