Большая загрузка файлов с помощью WebSocket
Я пытаюсь загрузить большие файлы (не менее 500 МБ, желательно до нескольких ГБ), используя API WebSocket. Проблема в том, что я не могу понять, как написать "отправить этот фрагмент файла, освободить используемые ресурсы, а затем повторить". Я надеялся, что смогу избежать использования чего-то типа 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), и он продолжает итерацию и добавляет все срезы в очередь, прежде чем пытаться ее отправить; там нет socket.afterSend, чтобы позволить мне правильно стоять в очереди, где я застрял.
Ответы
Ответ 1
EDIT: веб-мир, браузеры, брандмауэры, прокси, сильно изменились с тех пор, как был получен этот ответ. Прямо сейчас, отправка файлов с помощью websockets
могут быть выполнены эффективно, особенно в локальных сетях.
Websockets очень эффективны для двунаправленной связи, особенно если вы заинтересованы в том, чтобы выталкивать информацию (желательно небольшую) с сервера. Они действуют как двунаправленные сокеты (отсюда и их название).
Веб-узлы не похожи на правильную технологию для использования в этой ситуации. Особенно учитывая, что использование их добавляет несовместимости с некоторыми прокси, браузерами (IE) или даже брандмауэрами.
С другой стороны, загрузка файла просто отправляет запрос POST на сервер с файлом в теле. Браузеры очень хороши в этом, и накладные расходы для большого файла практически ничего не стоят. Не используйте веб-узлы для этой задачи.
Ответ 2
Я считаю, что метод send()
является асинхронным, поэтому он немедленно возвращается. Чтобы сделать это в очереди, вам нужно, чтобы сервер отправил сообщение клиенту после загрузки каждого фрагмента; клиент может затем решить, нужно ли отправить следующий фрагмент или сообщение "загрузить полный" на сервер.
Подобным образом, возможно, будет проще использовать XMLHttpRequest (2); он имеет встроенную поддержку обратного вызова и также более широко поддерживается, чем API WebSocket.
Ответ 3
Используйте веб-работников для обработки больших файлов, вместо этого делайте это в основном потоке и загружайте куски файлов с помощью file.slice()
.
Эта статья помогает обрабатывать большие файлы у рабочих. измените XHR на веб-узел в основной теме.
//Messages from worker
function onmessage(blobOrFile) {
ws.send(blobOrFile);
}
//construct file on server side based on blob or chunk information.
Ответ 4
Чтобы сериализовать эту операцию, сервер должен посылать вам сигнал каждый раз, когда срез принимается и записывается (или возникает ошибка), таким образом вы можете отправить следующий фрагмент в ответ на 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.
}
}
}
Ответ 5
Вы можете использовать https://github.com/binaryjs/binaryjs или https://github.com/liamks/Delivery.js если вы можете запустить node.js на сервере.
Ответ 6
Я думаю, что у этого проекта socket.io большой потенциал:
https://github.com/sffc/socketio-file-upload
Он поддерживает загрузку по частям, отслеживание прогресса и кажется довольно простым в использовании.