WebSocketでバイナリを送受信してみた(2)

クライアントからバイナリを送る確認ができたので、
バイナリに更にデータ乗っけて送ったりもらったりしてみる。

クライアント側

input:fileでファイルを参照したら、先頭にhelloworld文字列を追加した
バイナリデータとして送信する。

サーバ側からメッセージを受け取って、バイナリデータだったら
先頭の文字列と画像データに分けてそれぞれ表示する。

// BlobBuilder
BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
// URL
URL = window.URL || window.webkitURL;

// document
var doc = document;

// WebSocketを開く
var socket = new WebSocket('ws://' + location.host);
// バイナリデータはArrayBufferで取得する
socket.binaryType = 'arraybuffer';

// messageイベント
socket.addEventListener('message', function(evt) {
    var data = evt.data;
    if (data.constructor === String) {
        // Stringの場合、pタグで追加
        var p = doc.createElement('p');
        p.textContent = data;
        doc.getElementById('messages').appendChild(p);
    } else if (data.constructor === ArrayBuffer) {
        // ArrayBufferの場合、付加された文字列と画像データに分ける

        // 先頭から10バイトを8ビット符号なし整数値の配列に
        var arr = new Uint8Array(data.slice(0, 10));
        var key = [];
        for (var i = 0; i < 10; i++) {
            // キャラクタコードで文字列に変換して格納
            key.push(String.fromCharCode(arr[i]));
        }
        // 付加した文字列をpタグで追加
        var p = doc.createElement('p');
        p.textContent = key.join('');
        doc.getElementById('messages').appendChild(p);
        // 画像データ分をimgタグで追加
        var builder = new BlobBuilder();
        var img = new Image();
        builder.append(data.slice(10));
        img.src = URL.createObjectURL(builder.getBlob());
        doc.getElementById('images').appendChild(img);
    } else {
        alert('nanigashi');
    }
}, false);

// 文字列データをサーバに送信
doc.getElementById('sendText')
.addEventListener('click', function(evt) {
    socket.send('test');
}, false);

// fileを参照したらサーバに送信
doc.getElementById('image')
.addEventListener('change', function(evt) {
    var file = evt.target.files[0];
    var builder = new BlobBuilder();
    builder.append('helloworld');
    builder.append(file);
    // socket.send(file);
    socket.send(builder.getBlob());
}, false);

サーバ側

クライアントからバイナリデータを受け取ったら文字列と画像データに分解して、
文字列を返したあとに新たな文字列を先頭にくっつけた画像データを送信する。

// http server
var connect = require('connect');
var httpServer = connect()
.use(connect.static(__dirname + '/webroot'))
.listen(1234);

// WebSocket Server
var WebSocketServer = require('websocket').server;
var wsServer = new WebSocketServer({
    httpServer : httpServer,
    autoAcceptConnections : true
});

// クライアント接続イベント
wsServer.on('connect', function(client) {
    // クライアントからのメッセージ受信イベント
    client.on('message', function(message) {
        if (message.type === 'utf8') {
            // 文字列だったら文字列としてそのまま送信
            client.sendUTF(message.utf8Data);
        } else if (message.type === 'binary') {
            // バイナリだったら付加されている文字列を取り出し
            var src = message.binaryData;
            var text = new Buffer(10);
            src.copy(text, 0, 0, 10);
            // 受け取った文字列を返す
            client.sendUTF('receive:' + text.toString('utf8'));
            
            // 新たな文字列を付加して書き換えたバイナリデータとして送信
            var str = 'helloagain';
            var key = new Buffer(str);
            var buf = new Buffer(src.length);
            key.copy(buf, 0);
            src.copy(buf, 10, 10);
            client.sendBytes(buf);
        } else {
            console.log('nanigashi');
        }
    });
});

結果

ArrayBufferを使っていろいろやることで、バイナリデータを分割したりして
いろいろできた。ちょうどFirefoxも12からArrayBufferのsliceができるようになってた。