【问题标题】:Large file upload with WebSocket使用 WebSocket 上传大文件
【发布时间】:2012-06-20 06:16:19
【问题描述】:

我正在尝试使用 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 允许我正确排队,这就是我卡住的地方。

【问题讨论】:

  • 假设我不想依赖 Flash/Silverlight,我应该使用什么? XMLHttpRequest?我的印象是 WebSocket 的开销更少。
  • Websockets 的双向通信开销较小,是的,但是上传文件只是向服务器发送 POST 请求,文件在正文中。浏览器在这方面非常擅长,大文件的开销几乎为零。
  • 我正在考虑将其切成小块。我想我会尝试使用 File API 对其进行切片并使用 XMLHttpRequest 发送它,看看情况如何。谢谢您的帮助。如果您想根据上述信息以及任何其他建议做出回答,我很乐意接受它作为答案。
  • 只需将 xhr 调用替换为 websocket 发送即可获得大文件上传stackoverflow.com/questions/5053290/…
  • 是的,但我决定使用简单的 Ajax 调用而不是 WebSockets。实现是微不足道的,您只需要将下一个 send() 排队到上一个'完成。

标签: javascript html websocket large-files fileapi


【解决方案1】:

我相信send() 方法是异步的,这就是它会立即返回的原因。要使其排队,您需要服务器在每个切片上传后向客户端发送一条消息;然后客户端可以决定是否需要将下一个切片或“上传完成”消息发送回服务器。

使用 XMLHttpRequest(2); 这样的事情可能会更容易。它内置了回调支持,也比 WebSocket API 得到更广泛的支持。

【讨论】:

    【解决方案2】:

    使用网络工作者处理大文件,而不是在主线程中进行,并使用file.slice() 上传文件数据块。

    这个article 可以帮助您处理工作人员中的大文件。在主线程中更改 XHR 发送到 Websocket。

    //Messages from worker
    function onmessage(blobOrFile) {
     ws.send(blobOrFile);
    }
    
    //construct file on server side based on blob or chunk information.
    

    【讨论】:

    • 您的解决方案非常巧妙。我试过了,它非常适合 1Gb 及以上的大文件。我将它作为 websocket 单元测试的一部分,但是如果有人希望它重用,那么可以在那里找到源github.com/drogatkin/TJWS2/tree/master/1.x/test/html-js 目前的一个缺点是所有发送都是异步执行的,所以你无法控制文件何时发送完全。
    • WS 服务器可以在处理文件时简单地发回一条消息。它甚至可以在处理过程中发送消息来影响客户端的进度条,因为主线程没有被工作线程阻塞。
    • XHR 不在主线程上运行(除非明确设置为同步运行),因此线程不是使用 Web Worker 的理由。不同之处在于 XHR 在窗口的上下文中,如果选项卡关闭,它就会死掉,而 Web Worker 可以继续运行,直到浏览器进程终止。您可以在 Web Worker 中使用 XHR 和 WebSocket。
    【解决方案3】:

    为了序列化此操作,您需要服务器在每次接收和写入切片(或发生错误)时向您发送信号,这样您可以发送下一个切片以响应 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.
            }
        }
    }
    

    【讨论】:

    • 你认为FileSlicer 是一个标准库,但我在任何地方都找不到它。我想那是你自己创造的?
    • @CWSpear 这是我猜的问题
    【解决方案4】:

    编辑:自从做出这个答案以来,网络世界、浏览器、防火墙、代理发生了很大变化。现在,使用 websockets 发送文件 可以有效地完成,尤其是在局域网上。

    Websockets 对于双向通信非常有效,尤其是当您有兴趣从服务器推送信息(最好是小信息)时。它们充当双向套接字(因此得名)。

    Websocket 看起来不适合在这种情况下使用。特别是考虑到使用它们会增加与某些代理、浏览器 (IE) 甚至防火墙的不兼容性。

    另一方面,上传文件只是向服务器发送 POST 请求,文件在正文中。浏览器在这方面非常擅长,大文件的开销几乎没有。不要将 websocket 用于该任务。

    【讨论】:

    • dystroy,您的信息已过期。标准化的 WebSocket 协议 (IETF 6455) 支持发送和接收直接二进制数据(ArrayBuffer 和 Blob)。您正在考虑仅支持发送 UTF-8 数据(需要编码二进制数据)的旧 Hixie 协议。此外,IETF 6455 版本的 WebSocket 协议专门设计用于与现有代理和防火墙进行互操作。我已经广泛使用 WebSockets,没有看到您暗示的问题。请列举存在广泛问题的证据。
    • 我不会说您在 IETF 6455 上是错误的(特别是考虑到有关该主题的搜索导致您最近努力与 websockify 中的这一新规范兼容),并且此信息是欢迎,但世界并没有完全转变。见this proxy problem。此外,在this page 上寻找“浏览器支持”。基本上没有理由使用 websockets 上传文件。
    • 如果您删除整个第二段,那么我对您的回答没有任何问题,但第二段大多是错误的。 JSON 只是文本序列化/编码的一种方法,与 WebSocket 没有直接关系。 Base64 大约大 33%,但它并不占用大量 CPU(即使直接在 Javascript 中执行)。肯定有错误的中介,但没有普遍的问题。唯一仍然使用 Hixie 的主流浏览器是 iOS Safari(iOS 6 可能会改变这一点)。 Chrome、Firefox、IE 10、Opera(有但已禁用)都使用 IETF 6455。
    • 我从未告诉过 CPU。而且我知道您是新版本 websockets 的有力推动者,但是对于 OP(只想上传文件)认为现在没有兼容性问题是不公平的(我告诉过代理,例如)。
    • dystroy,请不要把话放在我嘴里。你的答案很好,但你的理由是有缺陷的。我没有说或暗示 WebSockets 是大文件上传的更好选择。如果您解决问题,我将删除反对票。您的编辑并没有改善这种情况。 “武士刀”是谁?
    【解决方案5】:

    如果您可以在服务器上运行 node.js,您可以使用 https://github.com/binaryjs/binaryjshttps://github.com/liamks/Delivery.js

    【讨论】:

      【解决方案6】:

      我觉得这个socket.io项目很有潜力:

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

      它支持分块上传、进度跟踪,而且看起来相当容易使用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-13
        • 2011-03-24
        • 2011-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-20
        相关资源
        最近更新 更多