web-dev-qa-db-fra.com

Importation de fichiers volumineux avec WebSocket

J'essaie de télécharger des fichiers volumineux (au moins 500 Mo, de préférence jusqu'à quelques Go) à l'aide de l'API WebSocket. Le problème est que je n'arrive pas à comprendre comment écrire "envoyer cette tranche du fichier, libérer les ressources utilisées puis répéter". J'espérais pouvoir éviter d'utiliser quelque chose comme Flash/Silverlight pour cela.

Actuellement, je travaille avec quelque chose comme:

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);
    }
}

Ensuite, je téléchargerais en utilisant:

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
        }
    }
}

Fondamentalement, cela renvoie immédiatement, bufferedAmount est inchangé (0) et il continue à itérer et à ajouter toutes les tranches à la file d'attente avant de tenter de l'envoyer; il n'y a pas de socket.afterSend pour me permettre de la mettre correctement en file d'attente, c'est là que je suis coincé.

25
Vlad Ciobanu

EDIT: Le monde du Web, les navigateurs, les pare-feu, les proxys ont beaucoup changé depuis cette réponse. Pour le moment, l'envoi de fichiers à l'aide de websockets peut être fait efficacement, en particulier sur les réseaux locaux.

Les Websockets sont très efficaces pour la communication bidirectionnelle, en particulier lorsque vous êtes intéressé à pousser des informations (de préférence petites) depuis le serveur. Ils agissent comme des sockets bidirectionnels (d'où leur nom).

Les Websockets ne semblent pas être la bonne technologie à utiliser dans cette situation. Surtout que leur utilisation ajoute des incompatibilités avec certains proxys, navigateurs (IE) ou même pare-feu.

À l'autre extrémité, le téléchargement d'un fichier envoie simplement une demande POST à un serveur avec le fichier dans le corps. Les navigateurs sont très bons dans ce domaine et la surcharge pour un gros fichier est vraiment proche de rien N'utilisez pas de Websockets pour cette tâche.

5
Denys Séguret

Je crois que la méthode send() est asynchrone, c'est pourquoi elle reviendra immédiatement. Pour la mettre en file d'attente, vous devez que le serveur renvoie un message au client après le téléchargement de chaque tranche; le client peut alors décider s'il doit renvoyer la tranche suivante ou un message "upload complete" au serveur.

Ce genre de chose serait probablement plus facile à utiliser XMLHttpRequest (2); il a un support de rappel intégré et est également plus largement pris en charge que l'API WebSocket.

10
Graham

Utilisez des travailleurs Web pour le traitement de fichiers volumineux au lieu de le faire dans le thread principal et téléchargez des morceaux de données de fichier à l'aide de file.slice().

Cette article vous aide à gérer des fichiers volumineux dans les travailleurs. changer l'envoi XHR à Websocket dans le thread principal.

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

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

Afin de sérialiser cette opération, vous devez que le serveur vous envoie un signal chaque fois qu'une tranche est reçue et écrite (ou qu'une erreur se produit), de cette façon, vous pouvez envoyer la tranche suivante en réponse à onmessage événement, à peu près comme ceci:

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
Demetrius Amadeus

Vous pouvez utiliser https://github.com/binaryjs/binaryjs ou https://github.com/liamks/Delivery.js si vous pouvez exécuter node.js sur le serveur.

3
Ibrahim Muhammad

Je pense que ce projet socket.io a beaucoup de potentiel:

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

Il prend en charge le téléchargement en bloc, le suivi des progrès et semble assez facile à utiliser.

0
Kesarion