Mam aplikację serwerową node.js i klienta przeglądarki. Wysyłanie ArrayBuffer
przeglądarki danych -> serwer działa idealnie, ale serwer -> przeglądarka powoduje otrzymanie ciągu znaków "[object ArrayBuffer]"
. Dzieje się tak w najnowszych wersjach Chrome i Firefox.Odbieranie danych WebSocket ArrayBuffer w przeglądarce - ciąg odbierający zamiast:
Serwer:
var serverPort = 9867;
// dependencies
var webSocketServer = require('websocket').server;
var http = require('http');
var players = {};
var nextPlayerId = 0;
// create http server
var server = http.createServer(function(request, response) { });
server.listen(serverPort, function() {
console.log((new Date()) + " Server is listening on port " + serverPort);
});
// create websocket server
var wServer = new webSocketServer({ httpServer: server });
// connection request callback
wServer.on('request', function(request) {
var connection = request.accept(null, request.origin);
connection.binaryType = "arraybuffer";
var player = {};
player.connection = connection;
player.id = nextPlayerId;
nextPlayerId++;
players[player.id] = player;
console.log((new Date()) + ' connect: ' + player.id);
// message received callback
connection.on('message', function(message) {
if (message.type == 'binary' && 'binaryData' in message && message.binaryData instanceof Buffer) {
// this works!
console.log('received:');
console.log(message);
}
});
// connection closed callback
connection.on('close', function(connection) {
console.log((new Date()) + ' disconnect: ' + player.id);
delete players[player.id];
});
});
function loop() {
var byteArray = new Uint8Array(2);
byteArray[0] = 1;
byteArray[0] = 2;
for (var index in players) {
var player = players[index];
console.log('sending: ');
console.log(byteArray.buffer);
player.connection.send(byteArray.buffer);
}
}
timerId = setInterval(loop, 500);
Klient:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script type="text/javascript">
window.WebSocket = window.WebSocket || window.MozWebSocket;
var connection = new WebSocket('ws://127.0.0.1:9867');
connection.binaryType = "arraybuffer";
// most important part - incoming messages
connection.onmessage = function (event) {
document.getElementById("log").innerHTML += typeof(event.data) + ' ';
document.getElementById("log").innerHTML += event.data + ' ';
if (event.data instanceof ArrayBuffer) {
// string received instead of a buffer
}
};
window.onkeydown = function(e) {
var byteArray = new Uint8Array(2);
byteArray[0] = 1;
byteArray[1] = e.keyCode;
connection.send(byteArray.buffer);
};
</script>
<div id='log'>Log: </div>
</body>
</html>
Co robię źle?
Edit:
Z node.js źródła websocket:
WebSocketConnection.prototype.send = function(data, cb) {
if (Buffer.isBuffer(data)) {
this.sendBytes(data, cb);
}
else if (typeof(data['toString']) === 'function') {
this.sendUTF(data, cb);
}
Więc jeśli używasz Uint8Array
, wysyła dane w postaci ciągu znaków, zamiast korzystania sendBytes
, jak sendBytes
potrzeb obiekt Buffer
. Tak jak w poniższej odpowiedzi, potrzebuję sendBytes
. Ponieważ nie mogę zdać ArrayBuffer
do sendBytes
, zrobiłem to na serwerze:
function loop() {
var buffer = new Buffer(2);
buffer[0] = 1;
buffer[1] = 2;
for (var index in players) {
var player = players[index];
console.log('sending: ');
console.log(buffer);
player.connection.send(buffer);
}
}
Teraz to działa.
Wniosek:
Chociaż Chrome i Firefox WebSockets .send()
bufor Uint8Array
jako dane binarne, wydaje node.js WebSockets wysłać go jako string
danych i trzeba bufor Buffer
wysłać binarny.
Zważywszy, że ArrayBuffer nie obsługują w IE aż do wersji 10 (której większość ludzi jeszcze nie ma), dlaczego nie wysłać danych tekstowych do klienta i nie ominąć tego problemu? –
Chcę użyć minimalnej możliwej liczby bajtów, ponieważ będę bardzo szybko wysyłać dane do wielu klientów i chcę pozostać na serwerze w sumie poniżej 10 kB/s włącznie z narzutem. Wygląda na to, że ArrayBuffer jest idealny do tego, nie obchodzi mnie, czy będzie on kiedykolwiek działał w IE szczerze. Potrzebuję go głównie do pracy w Chrome. – svinja
Spójrz na to: http://stackoverflow.com/a/11426037/4323 –