|
|
« Предыдущая тема | Следующая тема » |
Опции темы | Опции просмотра |
|
|
|||||
Регистрация: Jan 2012
Сообщений: 9
|
Данные по сети приходят с большим опозданием(Socket: as3.0 + java)
Добрый день. Не так давно работаю на actionscripts3.0, занялся созданием клиент-серверного взаимодействия и столкнулся с проблемой:
Ее суть состоит в том, что пакеты с сервера в клиент идут с задержкой, приходят частями, т.е. рвутся. Пробовал сначала писать первым байтом длину пакета, ничего не выходит с проверкой в клиенте. На сервер все уходит на ура, обратно возникают проблемы. Коды сервера и клиента прилагаются. Есть идеи, как решить? XML и фреймворки не хотелось бы. Насчет размера пакета не уверен, учитывается ли байт размера, писал и 12, и 13- трассировщиком ничего отловить внятного не смог. Из моих наблюдений: 1. Пакет всегда рвется на разные части, определяется каким-то великим рандомом. 2. Функция sData(см. код) вызывается ровно 2 раза(если 3 порции информации, то в третий раз вызова нет и обработка не происходит). Коды: AS3.0: package { import flash.display.Sprite; import flash.net.Socket; import mx.core.BitmapAsset; import flash.events.*; public class Main extends Sprite { [Embed(source = 'load11.jpg')] private var load11:Class; public var buff: int; public function Main():void { var load11:BitmapAsset = new load11(); var spr:Sprite = new Sprite(); spr.addChild(load11); addChild(spr); spr.addEventListener(MouseEvent.CLICK, func); function func(event:MouseEvent):void { trace("use socket"); var s: Socket = new Socket(); s. addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler); function ioErrorHandler(event:IOErrorEvent):void { trace("ioErrorHandler: " + event); } s.connect("localhost", 1011); var str: String; str = 'Test'; s.writeByte(10); s.writeUTF(str); s.writeByte(15); s.writeUTF(str); s.flush(); buff = -1; s.addEventListener(ProgressEvent.SOCKET_DATA, sData); function sData(event:ProgressEvent):void { if (buff == -1) { buff = s.readByte(); } if (buff == event.bytesLoaded) { var x:int, y:int, l:int; var z:String; var z1: String; x = s.readByte(); trace(x); y = s.readByte(); trace(y); z = s.readUTF(); trace(z); } else { trace("not ready: " + event.bytesLoaded + " " + buff ); } } } } } } /* ChatServer.java */ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; class Server { private static int port = 1011; /* port the server listens on */ public static void main (String[] args) throws IOException { ServerSocket server = null; try { server = new ServerSocket(port); /* start listening on the port */ } catch (IOException e) { System.err.println("Could not listen on port: " + port); System.err.println(e); System.exit(1); } Socket client = null; try { client = server.accept(); } catch (IOException e) { System.err.println("Accept failed."); System.err.println(e); System.exit(1); } DataInputStream in = new DataInputStream(client.getInputStream()); DataOutputStream os = new DataOutputStream(client.getOutputStream()); System.out.println("I Live!!!"); byte msg, def; String str; /* loop reading lines from the client and display them */ msg= in.readByte(); if (msg!=-1){ str= in.readUTF(); def=in.readByte(); str= in.readUTF(); System.out.println("Client says: " + msg + " "+ str + " : " + def); msg= (byte) (msg+17); def= (byte) (def *2); str="test"; os.writeByte(12);//Размер пакета os.writeByte(msg); os.writeByte(def); os.writeUTF(str); os.flush(); } } } Последний раз редактировалось VInchensoo; 12.02.2012 в 18:38. |
|
|||||
Регистрация: Nov 2010
Сообщений: 497
|
Никто не гарантирует, что даныне придут "пакетом". И в протоколе обмена нет понятия "порция" данных. Причин, по которым могут изменяться "размеры" получаемого блока данных - масса. Поэтому нужно правильно разбирать поток.
Цитата:
Вот это вот в общем случае неправильно. Данных может быть больше, чем вы считали в предыдущий раз (два сообщения подряд). Кстати, а bytesLoaded изменяется в следующем событии при чтении данных или нет? Просто либо при чтении следуюшей порции вы не получите правильных bytesLoaded (потому что считали уже один байт), либо не прочитаете вторую "порцию" информации (потому что bytesLoaded для нее будет суммой длин двух записей, а не длиной второй записи). |
|
|||||
Регистрация: May 2010
Адрес: пространство в положении
Сообщений: 219
|
где-то и когда-то говорили, что флеш(не air) с UDP не работает, а тока с TCP.
А так как Вы используете в сервере подключение через UDP, возможно в этом трабл.(т.к UDP у Вас будет слать пакеты, а дошли они или нет их уже не волнует) |
|
||||||
Регистрация: Jan 2012
Сообщений: 9
|
Цитата:
Причем на сервер все приходит сразу, там такой ошибки нет, эксепшина не было ни разу за время тестов. В любом случае, я поставил проверку, которая в теории должна работать, чтобы не читать данные, пока они не пришли до конца. Функции проверки буфера на непустоту я тоже не особо нашел. Цитата:
Цитата:
Что вы подразумеваете под тем, что данных может быть больше? Цитата:
Я пытался проверять оба способа, с учетом того, что от bytesLoaded отнимается 1 байт, когда мы считываем из буфера, и с учетом того, что этот байт не отнимается. Все тот же великий рандом наблюдается. Вообще, официальная документация adobe как-то крайней скупо поясняет, что такое bytesLoaded, и как его готовить. Я считал, что это число загруженных байт, которое не меняется, т.е. во время первой проверки считано 7 байт, во время второй 11, значит вторая часть- 4 байта. Еще 1 не дошел(ну это в данном случае). Другого способа(человечного) проверить, что данные пришли, и пришло именно столько, сколько нужно- я не нашел. Проверки на пустоту буфера я тоже не нашел. Может вы можете подсказать, как это вся правильно организовать именно на флеше, может с какими-то пруфами\примерами кодов. Буду премного благодарен. Цитата:
Последний раз редактировалось VInchensoo; 13.02.2012 в 21:27. Причина: Тег поправил |
|
||||||
Регистрация: Nov 2010
Сообщений: 497
|
Цитата:
Цитата:
Цитата:
Цитата:
Цитата:
|
|
|||||||
Регистрация: Jan 2012
Сообщений: 9
|
Цитата:
Про 20 кб- это скорее из области фантастики, аватарку передать или еще что, но, думаю, такие вещи лучше делать специальными компанентами типа URLLoader. Цитата:
Цитата:
Цитата:
Цитата:
1. При срабатывании события я считывал первый байт- число данных в буфере, которое должно быть 2. Далее делал проверку на socket.available, равно или нет числу байт, которой должно там лежать. Если равно, то вызываем обработчик пришедшего пакета. Снова все уперлось в эту магическую цифру: 2 вызова сокетдата. Я решил проверить ваше предположение, что событие не вызывается, если не было чтение из буфера после прихода данных. Каждый раз, когда что-то пришло, я вызывал проверку на то, что socket.available != 0 и считывал 1 байт(чтобы факт считывания был). Те же бараны в итоге- 2 считывания и все, больше события сокетдата не вызывается. Цитата:
Единственное, что я придумал, считать размер данных и запустить таймер, который бы проверял каждые Н мс размер буфера, если он заполнен как нужно- то считывать. Тут 2 подводных камня: 1. Вдруг событие сработает на 2 раза, а 3, не понятно, что будет с таймером. 2. Этот способ идиотский =) Может есть еще варианты/предположения, из-за чего это может быть? Я уже грешил в сторону ОС, но, думаю, вряд ли это связано, вряд ли проблема в железе или ОС. Может еще что-то можете предположить? |
|
|||||
Регистрация: Nov 2010
Сообщений: 497
|
Угу. Размер пакета вычисляется неправильно на стороне сервера. Правильный размер 1 + 1 + (2 + 4 * 1) = 8 байт. Формат записи writeUTF описан в javadoc.
А вообще порекомендую еще не руками вычислять размер "сообщения", а формировать сообщение и брать его размер. final ByteArrayOutputSteram baos = new ByteArrayOutputStream(); final DataOutput dos = new DataOutputStream(baos); writeMessage(daos); dos.close(); final byte[] message = baos.toByteArray(); sos.writeByte(message.length); sos.write(message); Цитата:
И на будущее рекоменду в случае проблем трейсить также и все приходящие (считываемые) данные. Вы бы заметили, что пакет меньше, чем написано. |
|
|||||
Регистрация: Jan 2012
Сообщений: 9
|
Цитата:
Цитата:
Цитата:
Цитата:
Из-за двойного стандарта по строкам и символам вижу 2 пути: 1. Проверять, в каком диапазоне символ и, по результатам проверки, считать 1 или 2 байта. 2. Сделать или найти аналог функции sizeof из цпп и использовать его для того, чтобы записать размер строки в байтах. Тут придется привести к двухбайтовому числу этот самый размер(хотя это не проблема, на java точно). Может что-нибудь посоветуете? Ибо получается слишком "обернутая обертка", простите за тавтологию, т.е. надстройка над надстройков. |
|
|||||
Регистрация: Nov 2010
Сообщений: 497
|
Цитата:
Ссылку на документацию вы не смотрели. Хотя там была неправильная ссылка . Вот правильная ссылка. Там цикл и два if'а внутри. Ничего сложного. Цитата:
Цитата:
|
|
|||||
Регистрация: Jan 2012
Сообщений: 9
|
Цитата:
Цитата:
Для флеша аналогичные методы присутствуют? Думаю, есть смысл сделать проверку, вдруг и до явы что-то не будет доходить сразу целиком. С другой стороны, методы java вроде бы ожидающие, так что не знаю, есть ли смысл? Цитата:
Последний раз редактировалось VInchensoo; 15.02.2012 в 21:55. |
Часовой пояс GMT +4, время: 19:58. |
|
« Предыдущая тема | Следующая тема » |
|
|