web-dev-qa-db-ja.com

WebSocketを使用した大きなファイルのアップロード

WebSocket APIを使用して大きなファイル(少なくとも500MB、できれば数GBまで)をアップロードしようとしています。問題は、「ファイルのこのスライスを送信し、使用されたリソースを解放してから繰り返す」という書き方がわからないことです。このために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はありません。

25
Vlad Ciobanu

編集:Webの世界、ブラウザ、ファイアウォール、プロキシは、この答えが出されてから大きく変わりました。現在、特にローカルエリアネットワークでは、websocketを使用したファイルの送信を効率的に行うことができます。

Websocketは、特にサーバーから情報(できれば小さい)をプッシュすることに関心がある場合、双方向通信に非常に効率的です。これらは、双方向ソケットとして機能します(そのため名前があります)。

Websocketは、この状況で使用するのに適切なテクノロジーのようには見えません。特に、それらを使用すると、一部のプロキシ、ブラウザ(IE)、さらにはファイアウォールとの非互換性が追加されることを考えると。

一方、ファイルのアップロードとは、POSTリクエストを本文にサーバーに送信することです。ブラウザはこれに非常に優れており、大きなファイルのオーバーヘッドはほとんどありません。そのタスクにwebsocketを使用しないでください。

5
Denys Séguret

send()メソッドは非同期であるため、すぐに戻ると思います。キューに入れるには、各スライスがアップロードされた後にサーバーがクライアントにメッセージを返送する必要があります。クライアントは、次のスライスを送信する必要があるのか​​、「アップロード完了」メッセージをサーバーに送り返すのかを決定できます。

この種のことは、おそらくXMLHttpRequest(2)を使用する方が簡単でしょう。コールバックサポートが組み込まれており、WebSocket APIよりも広くサポートされています。

10
Graham

メインスレッドで処理する代わりにWebワーカーを大きなファイルの処理に使用し、file.slice()を使用してファイルデータのチャンクをアップロードします。

この 記事 は、ワーカーで大きなファイルを処理するのに役立ちます。メインスレッドでWebsocketに送信するXHRを変更します。

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

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

この操作をシリアル化するには、スライスが受信および書き込まれるたびに(またはエラーが発生するたびに)サーバーからシグナルを送信する必要があります。これにより、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

Node.jsを実行できる場合は、 https://github.com/binaryjs/binaryjs または https://github.com/liamks/Delivery.js を使用できますサーバー。

3

このsocket.ioプロジェクトには多くの可能性があると思います。

https://github.com/sffc/socketio-file-upload

チャンクアップロード、進行状況の追跡をサポートし、かなり使いやすいようです。

0
Kesarion