【问题标题】:Send and receive binary data over web sockets in Javascript?在 Javascript 中通过 Web 套接字发送和接收二进制数据?
【发布时间】:2011-08-11 15:04:58
【问题描述】:

可以在 Javascript 中通过 Web 套接字发送和接收二进制数据吗?例如,我可以使用 Web 套接字实现 SSH 客户端吗?

【问题讨论】:

  • 乍得,你的问题得到解答了吗?如果可以,您能否选择您认为最好的答案,或者如果没有,您能否就您仍在寻找的内容提供反馈?

标签: javascript binary bit-manipulation websocket


【解决方案1】:

发送和接收二进制数据的一种安全的好方法是使用 base64 或 base128(其中 128 的开销仅为 1/7 而不是 1/3)。

是的,可以使用 SSH 客户端。

这方面的一个证据是,已经有很多解决方案可以在普通浏览器中运行,但其中大多数仍然需要自定义服务器端实现。 您可以在这里查看更多信息:http://en.wikipedia.org/wiki/Web-based_SSH

【讨论】:

  • -1,任何 UTF-8 兼容的编码都可以使用。此外,将插件描述为 100% Javascript 有点误导,因为插件需要下载和安装,并且通常不兼容跨浏览器。即插件正在使用普通 Javascript 上下文中不可用的浏览器工具。
【解决方案2】:

WebSockets 规范的下一个草案 (hybi-07) 正在大多数浏览器中实现,它将为协议和 API 添加内置的二进制支持。

但是,在那之前,WebSockets 有效负载被编码为 UTF-8。为了发送二进制数据,您必须使用某种方式将二进制数据编码为 UTF-8。

有很多选择,但这里有两个我用过的:

UTF-8

您实际上可以将字节流直接编码为 UTF-8。

用于编码和解码的 python 看起来像这样:

from codecs import (utf_8_encode, utf_8_decode,
                    latin_1_encode, latin_1_decode)

utf_8_encode(unicode(buf, 'latin-1'))[0]      # encode

latin_1_encode(utf_8_decode(utf8_buf)[0])[0]  # decode

在 Javascript 中:

chr = data.charCodeAt(N)  // to 'decode' at position N of the message

// Enocde array of bytes (0-255) to UTF-8
data = array.map(function (num) {
    return String.fromCharCode(num); }).join('');

UTF-8 编码注释:

  • 对于在值 0-255 之间均匀分布的二进制数据,有效负载的大小比原始二进制数据大 50%。

  • Flash WebSockets 模拟器 web-socket-js 可能在编码 0(零)时遇到问题。

Base 64

在python中:

from base64 import b64encode, b64decode

data = b64encode(buf)    # encode binary buffer to b64

buf = b64decode(data)    # decode b64 to binary buffer

在 Javascript 端对消息进行编码和解码:

data = window.btoa(msg)  // Encode to base64

msg = window.atob(data)  // Decode base64
msg.charCodeAt(N)        // Read decode byte at N

Base 64 音符:

  • 均匀分布的二进制数据 (0-255) 将比原始数据大 33%。

  • base64 编码的 python 端开销比 UTF-8 编码少。但是,解码 base64 需要更多的 Javascript 端开销(UTF-8 不需要在 Javascript 中解码,因为浏览器已经将 UTF-8 转换为 Javascript 原生 UTF-16)。

  • 更新:假设二进制数据编码为 UTF-8 字符串,如上所示,字符值范围为 0-255。具体来说,window.atob 不支持大于 255 的字符值。请参阅此mozilla bug。同样的限制也适用于 Chrome。

websockify

WebSockify 是一个代理/桥接器,它允许支持 WebSockets 的浏览器与任意二进制服务进行通信。创建它是为了允许noVNC 与现有的 VNC 服务器进行通信。 websockify 使用二进制数据的 base64 编码/解码,还提供了一个 websock.js 库以用于 Javascript。 websock.js 有一个类似于常规 WebSocket 的 API,但它透明地处理二进制数据,旨在与 websockify 通信。 免责声明:我创建了 websockify 和 noVNC。

ssh 客户端

从技术上讲,您可以通过 WebSockets 实现浏览器 ssh 客户端(我已经考虑过),但是,这需要在浏览器中进行 SSH 加密和解密,这会很慢。鉴于 WebSockets 具有加密的 WSS (TLS) 模式,在 WebSocket WSS 上执行普通 telnet 可能更有意义。

事实上,websockify 包含一个示例 telnet 客户端。

您可以像这样在 HOSTNAME 上启动 websockify(telnetd 来自 krb5-telnetd):

sudo ./websockify 2023 --web . --wrap-mode=respawn -- telnetd -debug 2023

然后导航到http://HOSTNAME:2023/wstelnet.html?hostname=HOSTNAME&port=2023

请参阅websockify README 了解更多信息。要使用 WSS 加密,您需要按照noVNC advanced usage wiki page 中的说明创建 SSL 密钥

【讨论】:

  • 投反对票的人是否愿意澄清为什么投反对票,以便我可以确定答案(如果可能)?谢谢。
  • base64 解决方案有问题。对我来说,如果必须编码的数据中包含无效的 UTF-8 字符,则对其调用 atob 会导致 chrome 上的“INVALID_CHARACTER_ERR: DOM Exception 5”或 firefox 上的“String contains an invalid character”。例如, atob("aGVsbG8=") 给出 "hello",但 atob("AQAAA") 会导致该错误。
  • @marc40000,您可以编码 (window.btoa) 任何字符串(无论其中包含何种奇怪的二进制/unicode 值)。要解码字符串 (window.atob),它必须是有效的标准 base64 编码。这意味着它只能使用标准的 64 个 base64 字符(A-Z、a-z、0-9、+、/),并且必须用“=”填充到四字节边界。在您的情况下,您的错误是因为“AQAAA”不是 base64 编码的。它太短而且没有填充。这有效: atob("AQAAAA==")
  • 关于浏览器二进制支持情况:autobahn.ws/testsuite/reports/clients/index.html
  • @Pacerier,Javascript 现在支持类型化数组(arraybuffers)和原生二进制类型的 Blob。这些可以直接通过 WebSocket 发送和接收,无需转换。当前版本的 Chrome、Firefox、Opera 支持这些类型(以及 Websocket 支持),并将在 IE10 中得到支持。
【解决方案3】:

嗯,也许 WebSockets 可以以某种方式与此结合:http://ie.microsoft.com/testdrive/HTML5/TypedArrays/

【讨论】:

  • 这已经是可能的了。见the spec
【解决方案4】:

现在你可以轻松发送和接收二进制数据了,这篇文章解释了很多想法:http://blog.mgechev.com/2015/02/06/parsing-binary-protocol-data-javascript-typedarrays-blobs/

这是我如何在浏览器中接收使用 python (my_nparray.tobytes()) 发送的二进制 numpy 数组:

ws = new WebSocket("ws://localhost:51234");
ws.binaryType = 'blob';
var buffer;

ws.onmessage = function (evt) {
    var reader = new FileReader();
    reader.readAsArrayBuffer(evt.data);
    reader.addEventListener("loadend", function(e)
    {
        buffer = new Uint16Array(e.target.result);  // arraybuffer object
    });
};

您可以使用以下方法将类型化数组转换为 javascript 数组:

Array.prototype.slice.call(buffer.slice());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-23
    • 2014-03-16
    • 2012-02-12
    • 1970-01-01
    • 1970-01-01
    • 2017-04-29
    • 2013-08-21
    • 2012-10-11
    相关资源
    最近更新 更多