【问题标题】:Sending a sub-segment of an ArrayBuffer over a WebSocket without copying通过 WebSocket 发送 ArrayBuffer 的子段而不复制
【发布时间】:2017-10-12 20:29:14
【问题描述】:

我正在用要通过WebSocket 发送的数据填充ArrayBuffer

数据大小可变,因此在序列化时我会根据需要动态扩展ArrayBuffer

但是,当序列化过程完成时,我通常在缓冲区末尾有我不想发送的未使用空间。

可以将所需的部分复制到新的ArrayBuffer,但这在内存和 CPU 方面是浪费的。

是否可以在不复制的情况下通过WebSocket 发送ArrayBuffer 的子部分?如果没有,是否有其他方法可以避免复制对性能的影响?


进行一些澄清编辑。

核心问题是WebSocket.send只接受DOMStringArrayBufferBlob。这些似乎都需要一个完整的缓冲区,而不是缓冲区的视图。

我不知道当我开始序列化时缓冲区会有多大,所以它从 64 字节开始,每次溢出时翻倍。这已经是 一些 复制,但我可以调整初始大小,以便溢出是例外。我要避免的是必须将序列化数据从过大的缓冲区中复制出来。

在伪 JS 中:

function serialiseAndSend(webSocket, message) {

    // Allocate a buffer (assume it's large enough)
    const buffer = new ArrayBuffer(64);

    // Serialise into that buffer, and obtain the number of bytes written (<= 64)
    const bytesWritten = serialise(buffer, message);

    // The first 'bytesWritten' bytes of 'buffer' contain my message, the rest is zeroed.
    //
    // I want to send that sub-portion without allocating another buffer.

    // This function would be great (buffer, start, count) but doesn't exist
    webSocket.send(buffer, 0, bytesWritten); 

    // Instead I think I have to allocate and send a copy
    const copy = buffer.slice(0, bytesWritten);
    webSocket.send(copy);
}

这种模式在其他平台/语言上很常见,似乎是 WebSocket API 的疏忽。但是我知道它是由经验丰富的开发人员设计的,我希望有一种方法可以完成我尚未遇到的事情。

【问题讨论】:

  • "核心问题是WebSocket.send只接受DOMStringArrayBufferBlob"这不准确。 .send() 也接受 TypedArray 作为参数。 “这个函数很好(缓冲、启动、计数)但不存在” 使用.subarray() 时确实存在该选项,如答案webSocket.binaryType = "arraybuffer"; let ab = new Uint8Array(buffer); let segment = ab.subarray(0, bytesWritten); webSocket.send(segment) 所示。注意,.slice().subarray() 不同
  • "核心问题是WebSocket.send只接受DOMStringArrayBufferBlob"注意,MDN不是规范,实际的@987654322 @ 还包括 ArrayBufferView 作为 .send() 的预期参数,它们是 TypedArrays。 MDN 文档可能应该被编辑和更新以包含该遗漏。

标签: javascript websocket


【解决方案1】:

编辑、更新

MDN 不是specification。关于WebSocket.send() 方法的MDN 文档省略了实际规范中包含的ArrayBufferView 选项,请参阅https://bugzilla.mozilla.org/show_bug.cgi?id=1409752


您可以使用.subarray() 为现有TypedArray 创建一个新视图

还要注意,这是在现有缓冲区上创建一个新视图; 对新对象内容的更改将影响原始对象 反之亦然。

【讨论】:

  • 谢谢,但我知道这种方法,它本身并没有帮助。如何通过 WebSocket 发送 TypedArray? send 方法需要一个缓冲区。
  • @DrewNoakes "如何通过 WebSocket 发送 TypedArray?"TypedArray 传递给 .send() plnkr plnkr.co/edit/qNLOByFtVh6REYfc8f4d?p=preview
  • @DrewNoakes 注意,也可以在本地尝试相同的代码,不使用外部服务,忽略net::ERR_NAME_NOT_RESOLVED 抛出的错误plnkr.co/edit/EKlkv8KhqjWqzfqO93jO?p=preview;见jsfiddle.net/adamboduch/JVfkt
  • 不错。这样可行。太好了,你提出了反对 MDN 文档的票。我实际上使用的是 TypeScript,send 上的参数类型是any,这在我的经验中对于lib.d.ts 来说是相当少见的。我会研究是否也可以收紧。
猜你喜欢
  • 2012-03-21
  • 2021-07-12
  • 1970-01-01
  • 1970-01-01
  • 2014-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多