четверг, 12 апреля 2012 г.

Тонкости с порядком байтов в Delphi и Flash

Не так давно начал писать клиент-сервер на AS3 и Delphi 2007 соответсвенно.
И хотел бы поведать о том, на чём мне пришлось задержаться на начальном пути.
Если точнее, то разговор пойдёт о некоторых щепетильных трудностях.
В этой теме я расскажу о разрозненности порядков байтов в флэшке и дэлфе.


Для начала стоит рассказать о формате моих пакетов, которыми я привык раскидываться по сетевым приложениям)
Пакет будет состоять из заголовка и тела.
Заголовок имеет такую структуру:
Delphi
type
  TPackNameType = word;
  TPackBodyType = integer;

  TPackHeader = packed record
    PackName      : TPackNameType;
    PackBodySize  : TPackBodyType;
  end;
Т.е. всё просто - имеем id типа пакета и длину его тела, которое в передаваемом потоке идёт сразу же за заголовком.
Все эти данные формируются в единый массив функцией move() и далее я вызываю метод SendData(var aData: TArrOfByte) менеджера сокетного подключения и массив полетел.

Теперь разберём пример пакета, где я и обнаружил разногласия - это пакет пингования:
PackName = 2; PackBodySize = 1; Body: [0];
В массиве для отправки(на сервере в Delphi 2007) он выглядит так: [2, 0, 0, 0, 1, 0, 0, 0, 0].
И мы сразу видим порядок байтов, который присущ компилятору D2007 - это обратный порядок байтов или по инглишу little endian, т.к. в нём сначало записываются младшии разряды числа.

И так, запрашиваю пинг с флеш клиента именно этим видом пакета, совершая такие действия:
ActionScript3
socket.writeInt(2); // 2-й тип пакета
socket.writeInt(1); // длина тела = 1 байт
socket.writeByte(0); // байт тела пакета

И сразу определилась такая неприятность, что после прочтения на серваке данной посылки, получается такой массив: [0, 0, 0, 2, 0, 0, 0, 1, 0].
А т.е. флешка имеет прямой порядок байт или big endian - сначало записываются старшии разряды числа.

Но благо то, что во флешке это оказалось лишь по умолчанию и в таких типах как Socket и ByteArray это легко изменяется следующим способом:
ActionScript3
const LITTLE_ENDIAN: String = "littleEndian";
...
var cliSock = new Socket();
cliSock.endian = LITTLE_ENDIAN;
...
var pb: ByteArray = new ByteArray();
pb.endian = LITTLE_ENDIAN;
От такая вот, своего рода, тонкость.

Комментариев нет:

Отправить комментарий