Загрузка большого файла с помощью WebSocket

Я пытаюсь загрузить большие файлы (не менее 500 МБ, предпочтительно до нескольких ГБ) с помощью WebSocket API. Проблема в том, что я не могу понять, как написать "отправить этот фрагмент файла, освободить используемые ресурсы, а затем повторить". Я надеялся, что смогу избежать использования чего-то вроде Flash/Silverlight для этого.

В настоящее время я работаю с чем-то вроде:

function FileSlicer(file) {
    // randomly picked 1MB slices,
    // I don't think this size is important for this experiment
    this.sliceSize = 1024*1024;  
    this.slices = Math.ceil(file.size / this.sliceSize);

    this.currentSlice = 0;

    this.getNextSlice = function() {
        var start = this.currentSlice * this.sliceSize;
        var end = Math.min((this.currentSlice+1) * this.sliceSize, file.size);
        ++this.currentSlice;

        return file.slice(start, end);
    }
}

затем я бы загрузил, используя:

function Uploader(url, file) {
    var fs = new FileSlicer(file);
    var socket = new WebSocket(url);

    socket.onopen = function() {
        for(var i = 0; i < fs.slices; ++i) {
            socket.send(fs.getNextSlice()); // see below
        }
    }
}

в основном это возвращает немедленно bufferedAmount не изменяется (0), и он продолжает итерацию и добавление всех срезов в очередь перед попыткой отправить его; нет сокета.afterSend, чтобы позволить мне правильно поставить его в очередь, где я застрял.

5 ответов


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

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

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

с другой стороны, загрузка файла-это просто отправка запроса POST на сервер с файлом в теле. Браузеры очень хороши в этом, и накладные расходы для большого файла действительно почти ничего. Не используйте websockets для этой задачи.


Я считаю send() метод является асинхронным, поэтому он немедленно вернется. Чтобы сделать его очередью, вам нужно, чтобы сервер отправил сообщение обратно клиенту после загрузки каждого фрагмента; клиент может решить, нужно ли ему отправить следующий фрагмент или" загрузить полное " сообщение обратно на сервер.

такого рода вещи, вероятно, было бы проще использовать XMLHttpRequest(2); он имеет встроенную поддержку обратного вызова, а также более широко поддерживается, чем WebSocket ПРИКЛАДНОЙ ПРОГРАММНЫЙ ИНТЕРФЕЙС.


используйте web workers для обработки больших файлов вместо этого в основном потоке и загружайте куски файловых данных с помощью file.slice().

этой статьи помогает обрабатывать большие файлы в рабочих. изменить XHR отправить в Websocket в основном потоке.

//Messages from worker
function onmessage(blobOrFile) {
 ws.send(blobOrFile);
}

//construct file on server side based on blob or chunk information.

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

function Uploader(url, file) {
    var fs = new FileSlicer(file);
    var socket = new WebSocket(url);

    socket.onopen = function() {
       socket.send(fs.getNextSlice());
    }
    socket.onmessage = function(ms){
        if(ms.data=="ok"){
           fs.slices--;
           if(fs.slices>0) socket.send(fs.getNextSlice());
        }else{
           // handle the error code here.
        }
    }
}

вы можете использовать https://github.com/binaryjs/binaryjs или https://github.com/liamks/Delivery.js Если вы можете запустить узел.js на сервере.