web-dev-qa-db-ja.com

JavascriptでWebソケットを介してバイナリデータを送受信しますか?

JavascriptでWebソケットを介してバイナリデータを送受信することは可能ですか?たとえば、Webソケットを使用してSSHクライアントを実装できますか?

29
Chad Johnson

WebSockets仕様の次のドラフト( hybi-07 )は、ほとんどのブラウザーに実装されており、プロトコルとAPIに組み込みのバイナリサポートが追加されます。

ただし、それまでは、WebSocketペイロードはUTF-8としてエンコードされます。バイナリデータを送信するには、バイナリデータをUTF-8としてエンコードする何らかの方法を使用する必要があります。

多くのオプションがありますが、ここで私が使用した2つがあります。

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%大きくなります。

  • python base64エンコーディングへのサイドオーバーヘッドはUTF-8エンコーディングよりも少なくなります。ただし、base64をデコードするためのJavascriptサイドオーバーヘッドは少し多くなります(UTF-8はブラウザはすでにUTF-8をJavascriptネイティブUTF-16に変換しているため、JavaScript。

  • Update:これは、バイナリデータが上記のように0〜255の範囲の文字値を持つUTF-8文字列にエンコードされることを前提としています。具体的には、window.atobは255を超える文字値をサポートしていません。この mozillaバグ を参照してください。同じ制限がChromeにも適用されます。

websockify

WebSockify は、WebSockets対応ブラウザが任意のバイナリサービスと通信できるようにするプロキシ/ブリッジです。 noVNC が既存のVNCサーバーと通信できるようにするために作成されました。 websockifyは、バイナリデータのbase64エンコード/デコードを使用し、Javascriptで使用するためのwebsock.jsライブラリも提供します。 websock.jsには、通常のWebSocketと同様のAPIがありますが、バイナリデータを透過的に処理し、websockifyと通信するように設計されています。 免責事項:私はwebsockifyとnoVNCを作成しました。

sshクライアント

技術的には、WebSocketを介してブラウザーのsshクライアントを実装することもできます(私はそれを検討しました)。ただし、ブラウザーでSSHの暗号化と復号化を行う必要があるため、処理が遅くなります。 WebSocketには暗号化された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の高度な使用法のWikiページで説明されているようにSSLキーを作成する必要があります

45
kanaka

バイナリデータを送受信する適切で安全な方法の1つは、base64またはbase128を使用することです(128のオーバーヘッドは、1/3ではなく1/7だけです)。

はい、SSHクライアントは可能です。

これの証拠は、一般的なブラウザーで実行されるソリューションがすでに多数存在することですが、それらのほとんどはカスタムサーバー側の実装を必要とします。詳細については、こちらをご覧ください: http://en.wikipedia.org/wiki/Web-based_SSH

9
sra

うーん、多分WebSocketsはこれと何らかの形で組み合わせることができます: http://ie.Microsoft.com/testdrive/HTML5/TypedArrays/

1
Chad Johnson

バイナリデータを簡単に送受信できるようになりました。この記事では多くの考えを説明します: 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());
1
Etienne Prothon