Бинарный протокол ProtoBuf
Не так давно (год назад), google предложил всем желающим использовать язык Protocol Buffers
Почитал, посмотрел - забавно. Перспективы использования большие.
есть порты на AS3, я тестировал этот:http://code.google.com/p/protobuf-actionscript3/
Хочу использовать как замену AMF.
В тестовом примере имитирую передачу данных по бинарному сокету.
Сразу появились проблемы: В том виде, как это сделано сейчас нормально можно работать только по схеме запрос/ответ, т.е. когда знаешь какой класс должен прийти в ответ.
При работе с "безымянным" сокетом в AMF можно узнать что за класс тебе пришел.
Попробуем реализовать это в ProtoBuf:
Все исходники тестового примера во вложении, здесь я акцентирую внимание, только на мои доделки)
итак главный класс: Main.as (читаем комменты)
package { import com.google.protobuf.Message; import com.google.protobuf.Person; import com.google.protobuf.PhoneNumber; import flash.display.Sprite; import flash.events.Event; import flash.net.getClassByAlias; import flash.net.registerClassAlias; import flash.utils.ByteArray; import flash.utils.getDefinitionByName; import flash.utils.getQualifiedClassName; /** * Тестовый класс работы с protoBuf - изменены исходники класса парсера * @author k0t0vich */ public class Main extends Sprite { public function Main():void { if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE, init); } private function init(e:Event = null):void { removeEventListener(Event.ADDED_TO_STAGE, init); // entry point //Регистрируем псевдонимы классов registerClassAlias("py.Person", Person); registerClassAlias("py.Number", PhoneNumber); // Создание и шифровка класса.-------------------------- //write var person:Person = new Person(); person.alias = "py.Person"; person.setName("John Doe"); person.setId(1234); person.setEmail("jdoe@example.com"); var number:PhoneNumber = new PhoneNumber(); var number2:PhoneNumber = new PhoneNumber(); number.setNumber("555-6789"); person.addPhone(number); number2.setNumber("123123123-12312"); person.addPhone(number2); trace("person: "+person); //Write it out to a any IDataOutput var bytes:ByteArray = new ByteArray(); person.writeToDataOutput(bytes); trace("writed bytes: " + bytes); //------------------------------------------------------- // имитация прихода данных от сокета onData(bytes); } //Данные от private function onData(bytes:ByteArray):void { bytes.position = 0; //read var message:Message = new Message(); //читаем не всё сообщение, а только имя псевдонима var alias:String = message.readClassAliasFromDataOutput(bytes); var classRef:Class = getClassByAlias(alias) as Class; var item:* = new classRef(); bytes.position = 0; item.readFromDataOutput(bytes); // выполняем метод конкретного класса item.changeModel(); } } }
Делаем ход конем: вводим поле alias
message Person { required string alias = 0; required string name = 1; required int32 id = 2; optional string email = 3; message PhoneNumber { required string number = 1; } repeated PhoneNumber phone = 4; }
Message.as
....... public function Message() { if (fieldDescriptors == null) fieldDescriptors = new Array(); setAlias(); } ........ // регистрируем поле псевдонима public var alias:String ; public function setAlias():void { registerField("alias", "", Descriptor.STRING, Descriptor.LABEL_OPTIONAL, 0); } ..... /** * Прочитать псевдоним сообщения * @param input */ public function readClassAliasFromDataOutput(input:IDataInput):String { var codedInput:CodedInputStream = CodedInputStream.newInstance(input); var tag:int = codedInput.readTag(); if (tag == 0) return ""; var fieldNum:int = WireFormat.getTagFieldNumber(tag); var desc:Descriptor = getDescriptorByFieldNumber(fieldNum); var item:* = codedInput.readPrimitiveField(desc.type); trace("item_alias "+item); return item; }
private function onData(bytes:ByteArray):void { bytes.position = 0; //read var message:Message = new Message(); //читаем не всё сообщение, а только имя псевдонима var alias:String = message.readClassAliasFromDataOutput(bytes); var classRef:Class = getClassByAlias(alias) as Class; var item:* = new classRef(); bytes.position = 0; item.readFromDataOutput(bytes); // выполняем метод конкретного класса item.changeModel(); }
Всего комментариев 5
Комментарии
13.08.2009 16:02 | |
Не подскажите, а какой версией вы пользовались?
Вы компилировали .proto файлы? Просто при компиляции .proto файлов компилятором этого проекта (http://code.google.com/p/protobuf-actionscript3/), результат получается плачевный. Код с синтаксическими ошибками. Типа: и Плюс, куча ошибок компилятора, типа, 1120: Обращение несуществующего свойства hasblablabla. Как Вы компилировали .proto файлы? Как Вы получили классы Person и PhoneNumber? |
18.08.2009 15:34 | |
Нет. классы я писал ручками.
во первых, как вы уже заметили, компилятор глючный, во вторых я добавляю вручную необходимые мне ф-ции changeModel До компилятора пока руки не дошли. переделывать его всё равно буду, т.к. у меня будет версия с расширением протокола ProtoBuf -> ProtoBuffWithAlias, причем для компиляции как as, так и py классов базовые классы тоже прописаны ручками. Кстати. у меня в коде баг. alias не обязательно будет писаться в поток первым, хотя у него и id=0, т.к. запись идет не по id а по forin. Как сделаю компилятор выложу изменения здесь. |
|
Обновил(-а) Котяра 18.08.2009 в 15:38
|
22.02.2011 15:43 | |
А поодержку Number случайно не делали?
Оно их не пишет( |
15.03.2012 12:18 | |
Котяра, как успехи с протобафом? Стоящая вещь?
|
Последние записи от Котяра
- Страх и ненависть в Нью-Дели или сборка мультипака для arm7 и x86 c Adobe AIR 14 в FB (16.06.2014)
- Нативный EventDispatcher в старлинге (27.11.2013)
- Нужны ошибки компиляции при создании экземпляра синглетона извне? Запросто! (13.09.2013)
- ARP - новый формат упаковки ресурсов (07.02.2013)
- DropShadowFilter и GlowFilter в Starling (16.01.2013)