Использование ProtoBuf-объекта полученного через сокет в Action Script 3

Posted on: January 27th, 2012 by Heart No Comments »

Как создать ProtoBuf-объект и отправить через сокет, можно посмотреть в этой статье.

Предполагается, что создан обычный сокет:

 

var socket:Socket = new Socket();


К сокету, добавляем обработчик события:

 

socket.addEventListener(ProgressEvent.SOCKET_DATA, eventSocketDataListener);

Внутри обработчика события считываем данные с сокета и создаем объект ProtoBuf:

 

socket.readBytes(buffer, buffer.length, socket.bytesAvailable);
 
try {
    message = new ProtoMessage();
    message.readExternal(buffer);
 
    buffer = new ByteArray();
 
    parseResponse(message);//об этом ниже
} catch(e:Error) {
 
}

Проблема в том, что если объект достаточно большой, то он может передаться через сокет не полностью. Как узнать, что передались все данные? Указанный выше пример делает проверку через конструкцию try/catch. После того, как мы считали все доступные байты сокета, мы пытаемся создать объект ProtoMessage. Весь фокус в том, что если байты объекта пришли не в полном объеме, то при попытке создания этого объекта выбросится исключение и мы будет ждать следующих данных от сокета. Когда следующие данные от сокета поступят, переменная buffer допишется недостающими данными и мы снова попробуем создать объект. Если в этот раз объект создастся без ошибок, мы переинициализируем переменную buffer и она будет готова для принятия данных о новом объекте.

На самом деле, конечно же нужно добавлять в поток байтов какой-то флаг, чтобы понять, какой объем данных нужно получить для создания объекта. Флагом может быть, например 32-разрядное число, в которое сервер запишет размер объекта при отправке. В этом случае код будет выглядеть следующим образом:

 

try {
    length = buffer.readInt();
    buffer.position = 4;
 
    if(length == buffer.length - 4) {		
        message = new ProtoMessage();
        //...
    }
} catch(e:Error) {
 
}

Перед попыткой создать объект, нужно считать его размер, добавленный в поток байтов сервером.

 

length = buffer.readInt();

Т.к. мы знаем, что мы считываем 32-разрядное число, то сдвигаем указатель, с которого будут зачитываться данные об объекте на 4 байта.

 

buffer.position = 4;

Дальше, сравниваем полученное число с размером буфера и пытаемся создать объект. На самом деле, реализаций подобного алгоритма можно придумать очень много. Это сильно упрощенный пример, который не претендует на эталон.

О функции parseResponse(data:*)

Тут все просто. С объектом переданным в функцию мы работаем как с обычным объектом Action Script. Для этого у нас скомпилировался специальный класс ProtoMessage. Все зависит от того, какие у вас заложены поля в этот объект, например:

 

var _par:Array = ProtoMessage(data).par;
var par:Param;
var len:int = _par.length;
 
for(var i:int = 0; i < len; i++) {
    par = Param(_par.pop());
    set(par);
}
 
function set(par:Param):void {
    if(!par) {
        return;
    }
 
    if(par.name == 'name') {
        params['name'] = par.value;		
    } else if(par.name == 'email') {
        params['email'] = par.value;						
    } else if(par.name == 'message') {
        params['message'] = par.value;
    }
}
 
control(ProtoMessage(data).command, ProtoMessage(data).status, ProtoMessage(data).serviceMessage, params);

В функцию control передаем данные об объекте и делаем нужные манипуляции.

Leave a Reply