nodejs二进制websocket模仿类型处理

coc*_*cco 5 javascript binary blob websocket node.js

我不是100%肯定,但是从我通过websocket发送blob(二进制数据)时看到的内容来看,该blob不包含任何文件信息。(此外,官方规范指出,wesockets仅发送原始二进制文件)

  1. 文件大小
  2. 模仿型
  3. 用户信息(稍后解释)

我正在使用https://github.com/websockets/ws

测试:

直接从输入文件发送Blob。

ws.send(this.files[0]) //this should already contain the info
Run Code Online (Sandbox Code Playgroud)

通过设置适当的mimetype文件,使用本地javascript api创建一个新的blob。

ws.send(new Blob([this.files[0]],{type:this.files[0].type})); //also this
Run Code Online (Sandbox Code Playgroud)

双方都只能获得有效的斑点,而没有任何其他信息。

是否有可能追加一个4kb的预定义json数据,该数据也转换为包含mimetype和filesize等重要信息的二进制文件,然后在需要时将其拆分为4kb?

{“ mime”:“ txt /纯文本”,“大小”:345} ____________ 4KB_REST_OF_THE_BINARY

要么

ws.send({"mime":"txt\/plain","size":345})
ws.send(this.files[0])
Run Code Online (Sandbox Code Playgroud)

即使第一个是最糟糕的解决方案,它也可以让我一次发送所有内容。

第二个有一个大问题:

这是一个聊天记录,允许同时发送文档,图像,音乐视频等文件。

在发送二进制数据之前,我可以在发送文件/用户信息时编写某种握手系统。

如果另一个人也发送了一个文件,因为它是异步的,则握手系统没有机会确定该文件对于正确的用户和模仿类型是正确的。

那么,如何在多用户异步环境中正确发送二进制文件?

我知道我可以转换为base64,但那要大30%。

顺便说一句 完全让Apple感到失望 ...虽然chrome可以正确显示每个二进制数据,但我的ios设备无法处理blob,只有图像将以blob或base64格式显示,甚至没有简单的txt文件。基本上只有<img>标签可以读取动态文件。

一切运作方式(现在):

  1. 用户发送文件
  2. nodejs获取二进制数据以及用户信息,但不是mimetype,filename,size。
  3. nodejs将原始二进制文件广播给所有用户。(无法指定用户和文件信息)
  4. 客户创建一个Bloburl(谁发送的?XD)。

编辑

我现在所拥有的:

客户端1(发送文件)

fileInput.addEventListener('change',function(e){
 var file=this.files[0];
 ws.send(new Blob([file],{
  type:file.type //<- SET MIMETYPE
 }));
 //file.size
},false);
Run Code Online (Sandbox Code Playgroud)

注意:file已经是blob了……但是,这通常是您创建指定mimetype的新blob的方式。

服务器(将二进制数据广播到其他客户端)

aaaaa和mimetype消失了...

ws.addListener('message',function(binary){
 var b=0,c=wss.clients.length;
 while(b<c){
  wss.clients[b++].send(binary)
 }
});
Run Code Online (Sandbox Code Playgroud)

客户端2(接收二进制文件)

ws.addEventListener('message',function(msg){
 var blob=new Blob([msg.data],{
      type:'application/octet-stream' //<- LOST
     });
 var file=window.URL.createObjectURL(blob);
},false);
Run Code Online (Sandbox Code Playgroud)

注意:m.data已经是blob了……但是,这通常是您创建一个新的blob来指定mimetype witch丢失的方式。

客户端2中,我需要模仿类型,自然地,我还需要有关用户的信息,这可以从客户端1服务器中检索到(不是很好的选择)...

Bre*_*dly 4

你对此有点不走运,因为 Node 不支持Blob接口,因此你使用 Node 以二进制形式发送或接收的任何数据都只是二进制。您必须拥有知道如何解释 Blob 对象的东西。

这是一个想法,请告诉我这是否有效。阅读它的文档后websockets\ws发现它支持发送和接收ArrayBuffers。这意味着您可以使用TypedArrays

这就是事情变得令人讨厌的地方。您在每个开头设置一定的固定 字节数来表示以 utf8 或其他方式编码的 mime 类型,其余部分包含文件的字节。nTypedArrayTypedArray

我建议使用,UInt8Array因为utf8字符是 8 位长,并且以这种方式编码时您的文本可能是可读的。至于文件位,您可能最终会将它们写在某处并为其添加结尾。

另请注意,无论是在 Node 中还是在浏览器中,这种解释方法都是双向的。

这个解决方案实际上只是类型转换的一种形式,您可能会得到一些意想不到的结果。MIME 类型字段的固定长度至关重要。

这里是图解说明的。复制、粘贴、将图像文件设置为您想要的任何内容,然后运行它。您会看到我设置的哑剧类型弹出。

var fs = require('fs');


///sf/ask/602650261/
function toUint8Array(buffer) {
  var ab = new ArrayBuffer(buffer.length);
  var array = new Uint8Array(ab);

  for (var i = 0; i < buffer.length; ++i) {
    array[i] = buffer[i];
  }

  return array;
}

//data is a raw Buffer object
fs.readFile('./ducklings.png', function (err, data) {
  var mime = new Buffer('image/png');
  var allBuffed = Buffer.concat([mime, data]);
  var array = toUint8Array(allBuffed);
  var mimeBytes = array.subarray(0,9); //number of characters in mime Buffer
  console.log(String.fromCharCode.apply(null, mimeBytes));
});
Run Code Online (Sandbox Code Playgroud)

以下是在客户端执行此操作的方法:

解决方案 A:获取包裹

获取缓冲区,是 Node 的浏览器 Buffer API 的实现。连接字节缓冲区的解决方案将像以前一样工作。您还可以附加诸如“收件人:”之类的字段以及不附加的字段。我确信,为了最好地服务客户而设置标题格式的方式将是一个不断发展的过程。

解决方案 B:老派

第 1 步:将 Blob 转换为 ArrayBuffer

注意:如何将 String 转换为 ArrayBuffer

var fr = new FileReader();
fr.addEventListener('loadend', function () {
//Asynchronous action in part 2.
  var message = concatenateBuffers(headerStringAsBuffer, fr.result);
  ws.send(message);
});
fr.readAsArrayBuffer(blob);
Run Code Online (Sandbox Code Playgroud)

第 2 步:连接 ArrayBuffer

function concatenateBuffers(buffA, buffB) {
  var byteLength = buffA.byteLength + buffB.byteLength;
  var resultBuffer = new ArrayBuffer(byteLength);
  //wrap ArrayBuffer in a typedArray/view
  var resultView = new Uint8Array(resultBuffer);
  var viewA = new Uint8Array(resultBuffer);
  var viewB = new Uint8Array(resultBuffer);
  //Copy 8 bit integers AKA Bytes
  resultView.set(viewA);
  resultView.set(viewB, viewA.byteLength);
  return resultView.buffer
}
Run Code Online (Sandbox Code Playgroud)

第 3 步:接收并重新发布

我不会重复如何将连接的 String 字节转换回字符串,因为我已经在服务器示例中完成了它,但是将文件字节转换为 mime 类型的 blob 相当简单。

new Blob(buffer.slice(offset, buffer.byteLength), {type: mimetype});
Run Code Online (Sandbox Code Playgroud)

此要点详细robnyman介绍了如何使用通过 XHR 传输的图像、将其放入本地存储以及在页面上的图像标记中使用它。