2012-06-18 18 views
17

Tôi đang cố tải lên các tệp lớn (ít nhất 500MB, tốt nhất là tối đa một GB) bằng API WebSocket. Vấn đề là tôi không thể tìm ra cách để viết "gửi lát này của tập tin, phát hành các nguồn lực được sử dụng sau đó lặp lại". Tôi đã hy vọng tôi có thể tránh sử dụng một cái gì đó như Flash/Silverlight cho việc này.Tải lên tệp lớn với WebSocket

Hiện nay, tôi đang làm việc với một cái gì đó dọc theo dòng:

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

Sau đó, tôi sẽ tải lên sử dụng:

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

Về cơ bản này trả về ngay lập tức, bufferedAmount là không thay đổi (0) và nó tiếp tục lặp lại và thêm tất cả các lát vào hàng đợi trước khi cố gắng gửi nó; không có socket.afterSend để cho phép tôi xếp hàng đúng cách, đó là nơi tôi bị kẹt.

+1

Giả sử tôi không muốn phụ thuộc vào Flash/Silverlight, tôi nên sử dụng những gì? XMLHttpRequest?Tôi đã ấn tượng rằng WebSockets có ít chi phí hơn. –

+2

Websockets có ít chi phí hơn cho truyền thông hai chiều, có, nhưng việc tải lên một tệp chỉ đơn giản là gửi một yêu cầu POST tới một máy chủ có tệp trong cơ thể. Trình duyệt là rất tốt ở đó và chi phí cho một tập tin lớn thực sự là gần không có gì. –

+0

Tôi đã cân nhắc việc cắt nó thành từng mảnh nhỏ hơn. Tôi đoán tôi sẽ thử cắt nó bằng cách sử dụng API File và gửi nó bằng cách sử dụng XMLHttpRequest, xem cách nó đi. Cảm ơn sự giúp đỡ của bạn. Nếu bạn muốn trả lời với thông tin trên, và có thể là bất kỳ lời khuyên nào khác, tôi vui vẻ chấp nhận nó như là câu trả lời. –

Trả lời

6

EDIT: Thế giới web, trình duyệt, tường lửa, proxy, đã thay đổi rất nhiều kể từ khi câu trả lời này được thực hiện. Ngay bây giờ, việc gửi tệp bằng cách sử dụng websockets có thể được thực hiện hiệu quả, đặc biệt là trên các mạng cục bộ.

Ổ cắm web rất hiệu quả cho giao tiếp hai chiều, đặc biệt là khi bạn quan tâm đến việc đẩy thông tin (tốt nhất là nhỏ) từ máy chủ. Chúng hoạt động như các ổ cắm hai chiều (do đó tên của chúng).

Websockets trông không giống như công nghệ phù hợp để sử dụng trong trường hợp này. Đặc biệt, việc sử dụng chúng cho biết thêm không tương thích với một số proxy, trình duyệt (IE) hoặc thậm chí là tường lửa.

Ở đầu bên kia, tải lên tệp chỉ đơn giản là gửi yêu cầu POST tới máy chủ có tệp trong phần nội dung. Trình duyệt là rất tốt ở đó và chi phí cho một tập tin lớn thực sự là gần không có gì. Không sử dụng websockets cho nhiệm vụ đó.

+22

dystroy, thông tin của bạn đã lỗi thời. Giao thức WebSocket chuẩn hóa (IETF 6455) hỗ trợ gửi và nhận dữ liệu nhị phân trực tiếp (ArrayBuffer và Blob). Bạn đang nghĩ về giao thức Hixie cũ chỉ hỗ trợ gửi dữ liệu UTF-8 (yêu cầu mã hóa dữ liệu nhị phân). Ngoài ra, phiên bản IETF 6455 của giao thức WebSocket được thiết kế đặc biệt để liên kết với các proxy và tường lửa hiện có. Tôi đã sử dụng WebSockets rộng rãi và không thấy các vấn đề bạn ngụ ý. Vui lòng trích dẫn bằng chứng rằng có những vấn đề lan rộng. – kanaka

+2

Tôi sẽ không nói rằng bạn sai trên IETF 6455 (đặc biệt khi tìm kiếm về chủ đề này dẫn đến những nỗ lực gần đây của bạn để làm việc về khả năng tương thích với tiêu chuẩn mới này trong websockify), và thông tin này được chào đón, nhưng thế giới không phải là ' t hoàn toàn chuyển đổi. Xem [vấn đề proxy này] (http://stackoverflow.com/questions/10947298/redirecting-websocket-traffic-on-port-80-with-lighttpd). Bên cạnh đó, hãy tìm "hỗ trợ trình duyệt" trên [trang này] (http://en.wikipedia.org/wiki/WebSocket). Và về cơ bản không có lý do * không * để sử dụng websockets để tải lên một tệp. –

+5

Nếu bạn xóa toàn bộ đoạn thứ hai thì tôi không có vấn đề gì với câu trả lời của bạn nhưng đoạn thứ hai hầu như là sai. JSON chỉ là một phương pháp serializing/mã hóa văn bản và không có gì trực tiếp để làm với WebSockets. Base64 lớn hơn khoảng 33%, nhưng nó không phải là CPU nặng (thậm chí làm nó trực tiếp trong Javascript). Có chắc chắn trung gian buggy nhưng không có vấn đề phổ biến rộng rãi. Trình duyệt chính duy nhất trong tự nhiên vẫn sử dụng Hixie là iOS Safari (và có thể iOS 6 sẽ thay đổi điều đó). Chrome, Firefox, IE 10, Opera (ở đó nhưng bị tắt) tất cả đều sử dụng IETF 6455. – kanaka

9

Tôi tin rằng phương pháp send() là không đồng bộ, đó là lý do tại sao nó sẽ trả về ngay lập tức. Để làm cho nó xếp hàng, bạn cần máy chủ để gửi một tin nhắn trở lại cho khách hàng sau khi mỗi lát được tải lên; sau đó khách hàng có thể quyết định xem nó có cần gửi lát tiếp theo hay thông báo "tải lên hoàn tất" trở lại máy chủ hay không.

Điều này có thể sẽ dễ dàng hơn khi sử dụng XMLHttpRequest (2); nó có hỗ trợ gọi lại tích hợp và cũng được hỗ trợ rộng rãi hơn API WebSocket.

4

Để serialize hoạt động này, bạn cần máy chủ để gửi cho bạn một tín hiệu mỗi khi một lát được nhận & bằng văn bản (hoặc một lỗi xảy ra), bằng cách này bạn có thể gửi các miếng tiếp theo để đáp ứng với onmessage sự kiện , khá nhiều như thế này:

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

Bạn tạo ra 'FileSlicer' làm thư viện chuẩn, nhưng tôi không thể tìm thấy nó ở bất cứ đâu. Tôi cho rằng đó sẽ là thứ bạn tự tạo ra? – CWSpear

7

sử dụng lao web cho các tập tin lớn chế biến thay vì làm việc đó trong chủ đề chính và tải lên khối dữ liệu tập tin sử dụng file.slice().

Điều này article giúp bạn xử lý các tệp lớn trong công nhân. thay đổi XHR gửi đến Websocket trong chủ đề chính.

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

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

Giải pháp của bạn thực sự mượt mà. Tôi đã thử nó và nó làm việc hoàn hảo cho các kích thước tập tin lớn như 1Gb và lên. Tôi đã làm nó như là một phần của một bài kiểm tra đơn vị cho websocket, tuy nhiên nếu ai đó muốn nó để tái sử dụng, sau đó nguồn có thể được tìm thấy ở đó https://github.com/drogatkin/TJWS2/tree/master/1.x/test/html -js One vẽ lại hiện tại tất cả gửi được thực hiện không đồng bộ, do đó bạn không có quyền kiểm soát khi tệp được gửi hoàn toàn. – Singagirl

+0

Máy chủ WS có thể chỉ gửi lại tin nhắn khi tệp được xử lý. Nó thậm chí có thể gửi tin nhắn trong quá trình xử lý để thực hiện thanh tiến trình trên máy khách, vì luồng chính không bị nhân viên chặn. –