在Javascript中通过Web套接字发送和接收二进制数据?

Cha*_*son 28 javascript binary bit-manipulation websocket

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

kan*_*aka 45

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
Run Code Online (Sandbox Code Playgroud)

在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('');
Run Code Online (Sandbox Code Playgroud)

UTF-8编码说明:

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

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

基地64:

在python中:

from base64 import b64encode, b64decode

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

buf = b64decode(data)    # decode b64 to binary buffer
Run Code Online (Sandbox Code Playgroud)

要在Javascript端编码和解码消息:

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

msg = window.atob(data)  // Decode base64
msg.charCodeAt(N)        // Read decode byte at N
Run Code Online (Sandbox Code Playgroud)

基地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错误.同样的限制适用于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
Run Code Online (Sandbox Code Playgroud)

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

有关更多信息,请参阅websockify README.要使用WSS加密,您需要创建一个SSL密钥,如noVNC高级使用Wiki页面所述

  • @ marc40000,你可以编码(window.btoa)任何字符串(不管它有什么奇怪的二进制/ unicode值).要解码字符串(window.atob),它必须是有效的标准base64编码.这意味着它只能使用标准的64 base64字符(AZ,az,0-9,+,/),并且必须用"="填充到四字节边界.在您的情况下,您的错误是因为"AQAAA"不是base64编码的.它太短而且没有填充.这有效:atob("AQAAAA ==") (3认同)
  • @Pacerier,Javascript现在支持类型化数组(arraybuffers)和Blob,它们是本机二进制类型.这些可以通过WebSocket直接发送和接收,无需转换.Chrome,Firefox,Opera的当前版本支持这些类型(以及Websocket支持),IE10将支持这些类型. (3认同)
  • 关于浏览器的二进制支持状态:http://autobahn.ws/testsuite/reports/clients/index.html (2认同)

sra*_*sra 9

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

是的,SSH客户端是可能的.

对此的证明是,已经有很多解决方案在常见的浏览器中运行,但是大多数解决方案仍然需要自定义服务器端实现.您可以在此处查看更多信息:http://en.wikipedia.org/wiki/Web-based_SSH


Eti*_*hon 6

现在你可以轻松地发送和接收二进制数据了,这篇文章解释了很多想法: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
    });
};
Run Code Online (Sandbox Code Playgroud)

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

Array.prototype.slice.call(buffer.slice());
Run Code Online (Sandbox Code Playgroud)