Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   можно ли загружать данные в URLStream с конкретного места? (http://www.flasher.ru/forum/showthread.php?t=132703)

mrMEM 18.11.2009 17:14

можно ли загружать данные в URLStream с конкретного места?
 
Допустим мы создаем поток URLStream и начинаем загружать в него данные
в какой-то момент времени, когда данные еще не полностью загружены мы вызываем функцию close() для того чтобы приостановить загрузку, предворительно сохранив загруженные данные в массив
Код AS3:

var stream:URLStream = new URLStream();
var tmpByteArray:ByteArray = new ByteArray();
stream.load(url);
...
srteam.readBytes(tmpByteArray);
stream.colse();

Возникает вопрос, возможно ли возобновить загрузку не считывая повторно данные сохраненные в tmpByteArray?

iflamberg 18.11.2009 17:52

гуглить по "flash HTTP-streaming", "flash эмуляция потокового видео через HTTP".
Вот, например, на первой жк странице http://crocodile2u.habrahabr.ru/blog/30402/.

Другого способа (без программирования на сервере) - нет.

mrMEM 18.11.2009 18:22

это не то
мне не нужна потоковая загрузка видео
задача в том чтобы закачивать файлы любого типа (сейчас для меня актуальны изображения)
если часть его была закачана, то нужно возобновить загрузку с того места где загрузка была приостановлена.

SamFR 18.11.2009 18:37

Цитата:

Сообщение от mrMEM (Сообщение 866507)
Возникает вопрос, возможно ли возобновить загрузку не считывая повторно данные сохраненные в tmpByteArray?

Вам и не нужно их повторно считывать, вам нужно дописывать в tmpByteArray вновь пришедшие данные. Я ж вам писал в прошлой вашей теме :)

Вам нужно передавать заголовок Range c содержимым "bytes=байт_с_которого_качать-". Далее начинать закачку и, например, каждый PROGRESS читать из потока количество байт, равное URLStream.bytesAvaliable, и дописывать их в конец tmpByteArray.

iflamberg 18.11.2009 18:57

2mrMEM:
Обычно такие вопросы возникают с видео, поэтому и давал соответсвующую инфу.
В общем случае: Чтобы сервер знал, что данные нужно отдавать не с начала, а с определенной позиции - нужно серверу передать с какой позиции передавать данные.
на сервере тогда должен быть код, например php-код, что-то типа:
Код:

$start = (int) filter_input(INPUT_GET, 'position', FILTER_VALIDATE_INT);
$fname = $_GET["fname"];
if ($start < 0) die("Incorrect request");
// open file for reading
$fp = fopen($fname, 'r');
$fsize = filesize($file);
if ($start > 0)
{
// seek to requested position
fseek($fp, $start);
header("Content-Length: " . (strlen($header) + $fsize - $start));
} else {
header("Content-Length: " . $fsize);
}
while(!feof($fp)) {
  print(fread($fp, 1024));
}
fclose($fp);

а url для загрузки должен быть соответственно что-то типа "get.php?fname=pic.jpg&position=1000"

mrMEM 18.11.2009 19:12

SamFR, куда передавать заголовок Range?
iflamberg, я правильно понимаю, что без PHP здесь не обойтись?

SamFR 18.11.2009 19:13

Конечно, всё зависит от серверной реализации, но стандарт HTTP/1.1 диктует именно такой способ получения частичного содержимого – с помощью заголовков Range и Content-Range. И большинство серверов, поддерживающих докачку (то есть выдачу частичного содержимого), реализуют именно этот стандарт.

Добавлено через 3 минуты
Заголовок Range передавать в запросе серверу. См. URLRequest.requestHeaders и класс URLRequestHeader. В ответе вам придёт заголовок Content-Range, указывающий, какой диапазон данных сервак будет отдавать. В некоторых случаях (хотя очень редко) он может не совпадать с тем, что вы запросили в Range.

Но, опять же повторюсь, сервак должен поддерживать этот способ закачки (то есть в ответе выдавать заголовок Accept-Ranges).

Добавлено через 6 минут
Также советую почитать спецификацию HTTP/1.1 или (даже лучше) статью Википедии про HTTP (http://ru.wikipedia.org/wiki/HTTP), а конкретно её раздел "Докачка и фрагментарное скачивание". Там всё очень подробно разжёвано.

mrMEM 18.11.2009 19:23

с URLRequest должен разобраться, спасибо

а как я могу узнать, что сервер поддерживает этот способ закачки?
вопрос состоит во-первых в том, чтобы как правильно выбрать сервер под эти нужды,
а во-вторых, могу ли я узнать об этом програмно, быть может try мне поможет?

SamFR 18.11.2009 19:27

Цитата:

Сообщение от SamFR (Сообщение 866529)
Но, опять же повторюсь, сервак должен поддерживать этот способ закачки (то есть в ответе выдавать заголовок Accept-Ranges).

И статью я вам не просто так порекомендовал :)

try тут не при чём.

Добавлено через 14 минут
Боюсь только, что определить это вы сможете только из-под AIR, если речь идёт о флэше. Сейчас посмотрел – событие httpResponseStatus объекта URLStream доступно только для эйра. Как и свойство HTTPStatusEvent.responseHeaders.

Где тут угроза безопасности – не знаю, но факт остаётся фактом.

mrMEM 20.11.2009 18:12

чтобы реализовать докачку, делаю так:
Код AS3:

resumeUrl = new URLRequest(url.url);        // создаем новый запрос с адресом старого запроса
var urlRequestHeader:URLRequestHeader = new URLRequestHeader("Range", "bytes="+byteArray.length);        // просим качать с конкретного места
resumeUrl.requestHeaders.push(urlRequestHeader);
 
try {
        stream.load(resumeUrl);
}
catch (err2:Error){
        // если не получается качать с заданного места, качаем с начала
        try {       
                stream.load(url);
        }
        catch (err2:Error){
                trace(err2);
        }
        trace(err2);
}

залил swf на сервер
http://reditstudio.ru/tmp/Test.swf,
проверяю докачку, запрос работает, но данные не верно интерпретируются при переводе в графический вид. подозреваю, что параметр byteArray.length неправильный.

byteArray - массив, в который заливаются данные из потока. это происходит так:

Код AS3:

private function streamProgressHandler(event:ProgressEvent){
        if( stream.bytesAvailable == 0 ) return;
        if (stream.connected){
                stream.readBytes(byteArray, byteArray.length);
        }
        trace(event);
 
        if (showLoading && timerFlag){
                timerFlag = false;
                loader.unload();
                loader.loadBytes(byteArray);
        }
 
}


SamFR 20.11.2009 18:52

А без докачки работает?
  1. Попробуйте закачать текстовый файл. Если всё нормально, ищите ошибку в создании изображения.
  2. Вообще говоря, читать из потока лучше определёнными порциями. Пусть, например, константа CHUNK задаёт минимальное количество байт, читаемых из потока, то есть порцию. Тогда:
Код AS3:

/**
 * Перед началом закачки.
 */

var data:ByteArray = new ByteArray(); //скачанные данные
var totalRead:uint = 0; //всего скачано
 
/**
 * Перед началом докачки.
 */

totalRead = data.length;
 
/**
 * В обработчике PROGRESS.
 * stream – ваш экземпляр URLStream.
 */

var toRead:uint = stream.bytesAvaliable;
if(toRead >= CHUNK){
        urlStream.readBytes(data, totalRead, toRead);
        totalRead += toRead;
}
 
/**
 * В обработчике COMPLETE.
 * stream – ваш экземпляр URLStream.
 */

var toRead:uint = stream.bytesAvaliable;
if(toRead){
        urlStream.readBytes(data, totalRead, toRead);
        totalRead += toRead;
}

Добавлено через 5 минут
Кстати, у вас может не получаться по следующей причине: ваш сервак просто не поддерживает докачку. Хоть это и маловероятно, но такой вариант всё-же имеется. Дело в том, что в этом случае ваш try..catch не сработает. Все пройдёт без ошибок, но данные начнут отдаваться с начала файла, как если бы вы не отправляли заголовка Range.

Узнать, поддерживает ли сервак докачку, можно только просмотрев ответные заголовки (в них должен присутствовать заголовок Accept-Ranges). К сожалению, из-под FP это сделать нельзя, только из-под AIR.

Поэтому, попробуйте с текстовым файлом и посмотрите, что получится. А также советую посмотреть диалог флешки с серваком тем же FireBug-ом. Заодно увидите, отправляет ли сервак Accept-Ranges, а также отправляет ли флешка Range.

Добавлено через 24 минуты
Вот ещё что. Подпишитесь-ка на событие HTTPStatusEvent.HTTP_STATUS вашего экземпляра URLStream, и в обработчике протрейсите

Код AS3:

trace('Status code: ' + (event as HTTPStatusEvent).status);

Чему он равен?

Если после запроса, содержащего Range, статус-код равен 200, то сервак докачку не поддерживает. Если же он равен 206, что указывает на выдачу частичного содержимого, то всё нормально и проблема, скорее всего, в чём-то другом.

Добавлено через 32 минуты
Цитата:

Сообщение от iflamberg (Сообщение 866501)
Другого способа (без программирования на сервере) - нет.

Вы не правы. Как тогда, по-вашему, работают программы типа DownloadMaster или встроенная в Оперу качалка? Они ведь реализуют докачку практически со всех серваков)

Из-под флеш-плеера докачку реализовывать не приходилось, но из-под AIR проблем особых не возникло. К счастью, статус-код можно посмотреть и из флеш-плеера, поэтому тут тоже проблем быть не должно, хоть и будет чуть менее надёжно без анализа ответных заголовков.

mrMEM 25.11.2009 14:40

up message

Добавлено через 27 минут
Цитата:

Сообщение от SamFR (Сообщение 867145)
Кстати, у вас может не получаться по следующей причине: ваш сервак просто не поддерживает докачку.

качал файлы Download Master-om - разбивает на части, и после приостановки докачивает

Цитата:

Сообщение от SamFR (Сообщение 867145)
Дело в том, что в этом случае ваш try..catch не сработает. Все пройдёт без ошибок, но данные начнут отдаваться с начала файла, как если бы вы не отправляли заголовка Range.

Это то, что нужно. Данные должны отдаватсья с начала, если невозможно получить данные с контрольной точки. Почему-то если запускаю swf со своего компьютера, а не с сервера и качаю фотографии с сервера, без try..catch получаю ошибку; в представленном варианте кода данные качаются с начала.

кстати событие HTTPStatusEvent.HTTP_STATUS почему-то срабатывает после закачки..

SamFR, спасибо за дельные советы

SamFR 25.11.2009 16:12

Цитата:

Сообщение от mrMEM (Сообщение 868194)
Почему-то если запускаю swf со своего компьютера, а не с сервера и качаю фотографии с сервера, без try..catch получаю ошибку; в представленном варианте кода данные качаются с начала.

Скорее всего, это ошибка безопасности, так как котент, запущенный в локальной зоне безопасности, не может обращаться к сети.

Цитата:

Сообщение от mrMEM (Сообщение 868194)
кстати событие HTTPStatusEvent.HTTP_STATUS почему-то срабатывает после закачки..

Так и должно быть. И это основная проблема, так как узнать, что сервер не поддерживает докачку и отдавал нам данные с начала, мы сможем только после завершения закачки.

Цитата:

Сообщение от mrMEM (Сообщение 868194)
SamFR, спасибо за дельные советы

Да не за что :)


Часовой пояс GMT +4, время: 06:16.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.