![]() |
|
||||||||||
|
|||||||
|
|
« Предыдущая тема | Следующая тема » |
| Опции темы | Опции просмотра |
|
![]() |
![]() |
|
|||||
|
Регистрация: Jan 2010
Сообщений: 211
|
Думал, что проблемы такого плана мне давно по плечу, однако сложность отслеживания состояний на клиенте и количество участков, где возможны проблемы, вызывают значительные затруднения.
1. Страница, javascript (функция, связывающая скрипт с флешем, упрощенная): function sendData(data){
var flash = (navigator.appName.indexOf("Microsoft") != -1) ? window["comet"] : document["comet"];
if (typeof(flash) == undefined || flash == undefined || flash == null) return setError(/* my function */);
flash.sendData(data);
};
public class Main extends Sprite { private var _socket:MySocket; function Main() { ... _socket = new MySocket(); _socket.addEventListener(CustomEvent.RECIEVE_DATA_EVENT, server_message); ... ExternalInterface.addCallback("sendData", client_message); } ... private function server_message(event:Event):void { try { var e = CustomEvent(event); ExternalInterface.call("recieving", e.message); } catch(exception:Error) {...} } private function client_message(data:String):void { _socket.sendPacket(data); } } public dynamic class CustomEvent extends Event { private var _message:String; private var _message_type:String; public static const RECIEVE_DATA_EVENT:String = "RECIEVE_DATA_EVENT"; public function CustomEvent(type:String, message:String, message_type:String) { super(type); _message = message; _message_type = message_type; } ... } public class MySocket extends Socket { public function MySocket() { addEventListener(Event.CLOSE, closeHandler); addEventListener(Event.CONNECT, connectHandler); addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler); addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler); ... } private function closeHandler(event:Event):void {...} private function connectHandler(event:Event):void {...} private function ioErrorHandler(event:IOErrorEvent):void {...} private function securityErrorHandler(event:SecurityErrorEvent):void {...} private function socketDataHandler(event:ProgressEvent):void {...} public function sendPacket(data:String):void { var packet:String = '{"data":' + data + '"}'; try { writeUTFBytes(new Number(packet.length).toString(16) + '\r\n' + packet + '\r\n'); flush(); } catch(exception:IOError) {...} } } Код флеша я для поста сильно упростил, реально он значительно сложнее, я передаю несколько параметров, на основе которых формирую пользовательский объект, который передается и обрабатывается разными классами. Также на выходе флешки формируется достаточно сложная строка JSON (использую библиотеку для формирования). Уверен, что проблемы в упущенных деталях нет. Уже пару месяцев использую такую цепочку для обмена данными и все работало как часики - быстро, удобно и без проблем. Проблема появилась, когда я на странице посредством js в цикле делаю много вызовов функции sendData(data) - от 3 и более. Логгирование перед отправкой во флеш показывает, что данные отправляются корректною. Скажем, посылаем строки "ааа", "bbb", "ccc". На сервере на входе получаем первый пакет, в котором корректное значение - "ааа", а потом второй пакет, в котором значения "bbb" и "bbb". Если отправлять не 3 пакета, а, скажем, 5 пакетов, то на входе получаем те же 2 пакета, в первом все корректно, а во втором - 4 значения "bbb". Так как на сервере реализован механизм разделения целого пакета на составные, то проблема не в этом, а именно в передаваемых данных. Подозреваю, что моя проблема связана как-то с однопоточностью выполнения AS3 и частым дерганьем ее со страницы. Однако мыслей по преодолению ее немного. Есть мысль не делать цепочку вызовов во флеше: "вызов интерфейса со страницы" - "вызов функции-обработчика" - "вызов функции-отправителя" - "отправка пакета", а на первом же этапе помещать получаемые флешкой данные в очередь, а в классе пользовательского сокета организовать изъятие данных из очереди. Правда, немного затрудняюсь в реализации (в Java это делается очень просто - через блокирующие или неблокирующие механизмы и треды, а вот в AS3 как это сделать грамотно - пока не очень представляю). На сегодняшнем этапе я мог бы обойти проблему, помещая данные из цикла в один пакет и отправляя только его, однако это не факт, что завтра она же не выплывет снова (точнее, она выплывает при попытке отправки нескольких запросов по статистическим данным при загрузке страницы - обошел это путем вложенности запросов в коллбеки). Также можно было бы делать очередь и на странице с изъятием следующих данных по таймауту, однако это, во-первых, "через зад..цу", а во-вторых, компы клиентов могут быть разными и делать универсальный длинный таймаут или подбор в зависимости от клиента, на мой взгляд, слишком "некошерно". Поэтому вопрос к знающим и использующим сокеты для взаимодействия с сервером - как вы справляетесь с большим количеством отправляемых пакетов? Спасибо. Добавлено через 2 часа 11 минут Все-таки кое в чем был неправ ... Анализируя двоичные данные, полученный на сервере, обнаружил интересную закономерность (пакеты слегка отредактированы, так как содержимое закодировано при отправке и распаковывается непосредственно в функциях обработки): Отправляем 3 пакета с данными "aa", "bbbb", "cccccc". Ловим на сервере: Пакет 1. Получен, обработан и отправлен. - Read 154 bytes: {"action_id":210,"action_type":102,"sender":1,"message":"{'title':'aa','owner':9}","message_id":"xxx"} Пакет 2 (пришел как спаренный их 2-го и 3-го отправленного). - Read 156 bytes: {"action_id":210,"action_type":102,"sender":1,"message":"{'title':'bbbb','owner':9}","message_id":"xxx"} - Read 158 bytes: {"action_id":210,"action_type":102,"sender":1,"message":"{'title':'bbbb','owner':9}","message_id":"xxx"}{"action_id":210,"action_type":102,"sender":1,"message":"{'title':'cccccc', 'owner':9}","message_id":"xxx"} Как видно, флеш при отправке "склеивает" уже отправленный пакет и новый, или просто не очищает буфер отправки после flush(). Почему? При этом длина пакета соответствует правильному, отправляемому в настоящий момент пакету. Если отправлять большее количество данных, то количество принимаемых пакетов будет правильным, длина каждого пакета правильна, но нужный пакет будет находиться всегда в самом конце получаемых данных. Добавлено через 6 часов 44 минуты Ёпс! Стыдно-то как ... Я очень давно экспериментировал с созданным механизмом обработки полученных данных (что-то у меня было проблемно с размером получаемого пакета) и добавил "+=" к стринговой переменной, в котороъ сохраняется значение пакета. Эксперимент не вернул к исходному, отсюда и ошибка ![]() Приношу извинения, стыдно, но все проблемы мигом исчезли. Извините. |
![]() |
![]() |
Часовой пояс GMT +4, время: 02:54. |
|
|
« Предыдущая тема | Следующая тема » |
|
|