Writing and Parsing Binary Data in NodeJs - javascript

So i wrote server tcp application with nodejs, here is the code:
Server Side
var host = "127.0.0.1";
var port = 15010;
// Instruct server to start Listening for incoming connection
function listen() {
// Start Server
console.log('Server Started [' + host + ':' + port + ']');
var server = net.createServer(function(socket) {
// Send Connection Success
socket.write('Success');
socket.pipe(socket);
// Server Received a new Connection from Client
console.log('Client was Connected [' +
socket.remoteAddress + ':' + socket.remotePort + ']');
// When Server Received data from Client.
socket.on('data', function(resp) {
console.log('We received following data: ' + resp);
// probably going to tell server whether my Game is about to exit
// so the server will close the current socket.
// and also won't caught ECONNRESET exception lol.
});
// When Client Connection is Ended.
socket.on('end', function() {
console.log('Connected Ended ');
// Destroy closed socket
socket.destroy();
});
// When Client Connection is Closed.
socket.on('close', function() {
console.log('Client was Closed ');
// Destroy closed socket
socket.destroy();
});
// When Server caught an exception
socket.on('error', function(ex) {
// Server will caught an exception if client was disconnected from client side
// It's appear the server was not expected when client is disconnected.
// Currently, i will salvage it as much as i can until i find better solution (or this is the best solution(?) lol) but it's doesn't matter for now..
if (ex.code == 'ECONNRESET') {
console.log('Ending current session of Client');
}
});
}).listen(port, host);
it's work well when handling incoming string data.
However i was wondering how to parse a binary data that received by the server from client.
I am using following code in my game to send data to server:
Client Side
// Use memory stream
using (MemoryStream ms = new MemoryStream())
{
// Use binary writer also
BinaryWriter writer = new BinaryWriter(ms);
// Write int16 (2 bytes)
writer.Write((short)id);
// Write int32 (4 bytes)
writer.Write((int)status);
// Write int64 (8 bytes)
writer.Write((long)score);
// Write float (4 bytes)
writer.Write((float)freq);
// I can even write string on it easily (assuming username string is 2 chars)
writer.Write(Encoding.UTF8.GetBytes(username));
// The stream position should be
// 2 + 4 + 8 + 4 + 2 = 20
Console.WriteLine(ms.Position.ToString());
// Send data to server
socket.Send(ms.GetBuffer());
}
In C#, I could handle it easily with following code (the code is also similar like send data too):
// Receiving data from the Server
byte[] resp;
socket.Receive(out resp);
// Could be handled with Memory Stream too
using (MemoryStream ms = new MemoryStream(resp))
{
// This time i will use BinaryReader
BinaryReader reader = new BinaryReader(ms);
// Read int16 (2 bytes)
short id = reader.ReadInt16();
// Read int32 (4 bytes)
int status = reader.ReadInt32();
// Read int64 (8 bytes)
long score = reader.ReadInt64();
// Read float (4 bytes)
float freq = reader.ReadSingle();
// Read String (assuming data is 2 bytes)
string username = Encoding.UTF8.GetString(reader.ReadBytes(2));
// Same like before
// The stream position should be
// 2 + 4 + 8 + 4 + 2 = 20
Console.WriteLine(ms.Position.ToString());
}
but how i can parse it in NodeJS?
can someone tell me which classes in NodeJS that i should use to achieve this? (providing an example like I did in C# is much more appreciated)
any ideas?
sorry for my bad English, thanks in advance
EDIT
So I figured a bit, it seem received data is a Buffer object as default (thanks for #dandavis)
here my attempt and its working:
// When Server Received data from Client.
socket.on('data', function(resp) {
// It's kinda hard (not effective(?))
// since i need to specify offset each time im trying to read something
// probably i will write simple class, or does anyone know class
// that could handle like BinaryReader in C#?
// Read int16 (2 bytes)
var id = resp.readInt16LE(0);
// Read int32 (4 bytes)
var status = resp.readInt32LE(2);
// I don't know how to read int64
var score = // there is no readInt64LE ??
// Read float (4 bytes)
var freq = resp.readFloat(14);
// Read string, assuming encoded with utf8 with 2 characters
var username = resp.toString('utf8', 18, 2);
});
But there are few problem:
I don't know how to read (and write) int64
in API doc, it's doesn't describe what the difference between LE and BE (i can only speculate it was Little Endian and Big Endian, but i don't know them)
Could you guys tell me how to read int64 and give short explanation about LE and BE?
thanks!

Related

Does a javascript websocket encrypt any data being sent?

So I am trying to setup a client websocket in a Javascript file talking to a server written in C#.
Client:
var socket = new WebSocket("ws://localhost:11000");
function barf() {
socket.send('asdf');
}
socket.onmessage = function(e){
console.log(e.data);
};
Server:
IPHostEntry ipHostInfo = Dns.GetHostEntry("localhost");
IPAddress ipAddress = ipHostInfo.AddressList[1];
TcpListener listener = new TcpListener(ipAddress, 11000);
try
{
listener.Start();
TcpClient client = listener.AcceptTcpClient();
message = client.GetStream();
int i = message.Read(bytes);
string data = Encoding.ASCII.GetString(bytes, 0, i);
string key = new System.Text.RegularExpressions.Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim();
Byte[] response = GetHandshakeResponse(key);
message.Write(response, 0, response.Length);
bytes = new Byte[1024];
i = message.Read(bytes);
Console.WriteLine(Encoding.ASCII.GetString(bytes));
}
The issue is that when I call the function 'barf' in my Javascript file, the server spits out a different message each time as if it were being encrypted. I have tried using different encodings and I can't seem to end up with exactly 'asdf' on the server. Does anyone have any insight? Thanks!
If you want to encrypt communication over web sockets, use the wss protocol instead of ws.
Also, I don't think your test is meaningful, because you haven't run it with a server socket server on the back end.
Creating a "Hello World" WebSocket example

Node.js [net library]: How to make the buffer object a string?

I am fairly new to Node.js, and I am creating a TCP client that sends and receives data from a certain server.
My problem is with the "data" event emitted when data is received through the socket.
client.on('data', function(data) {
console.log('[TCP] Client received: ' + data); // Logs the message as it is supposed to be.
console.log(data.split(" ")); // Does not work because it says that data is not a string
});
I tried toString(data) but it did not output it as it was logged by the console.
So my question is: How can I convert this object to a string as it is logged in the console?
Thank you for your input :)
if data is a Buffer instance as it looks like, it's
client.on('data', function(data) {
console.log(data.toString('utf8'));
})

how to route different data types over Websockets?

I have to send a lot of ArrayBuffers (audio voice data) over a websocket server. The Problem is, that the client has to know which type of ArrayBuffer the incoming data is (Uint8 / Uint16 / Float32...). The type can change on the fly if the user switch to an other audio quality.
What is the best way to inform the client about the array type ?
Ideas so far:
Put an extra prefix byte to the array (this might be slow because i have to create a new arrayBuffer for each audio chunk)
Using different routes like /16float or /uint8 to know which data is coming. (I have not found any information how this is done with websockets)
Is there an better way to do this? Can anyone give me an example how URL-Path routes with websockets work ?
EDIT:
I implemented prefix bytes to send information about client and array type, but still interested in better/other solutions.
Cracker0dks, why are you using pure websockets and not a library. With primus you can use substream - namespace - which is more or less exactly what you want - you can also use binnary parser with primus.
Socket.io is also an option but they are not as good as primus.(in my opinion)
Currently its the most supported/ stable / complete solution for ws
// server side:
var primus
, server
, substream
, http
, Uint8
, Uint16
, Float32
;
Primus = require('primus');
http = require('http');
substream = require('substream');
server = http.createServer();
primus = new Primus(server);
primus.use('substream', substream);
server.listen(8000);
primus.on('connection', function (spark) {
Uint8 = spark.substream('Uint8');
Uint16 = spark.substream('Uint16');
Float32 = spark.substream('Float32');
Uint8.on('data', function (data) {
console.log(data); //we recieve data from client on Uint8 ('to server')
});
Uint16.on('data', function (data) {
console.log(data); //we recieve data from client on Uint16 ('to server')
});
Float32.on('data', function (data) {
console.log(data); //we recieve data from client on Float32 ('to server')
});
Uint8.write('to client'); // write data to client to Uint8
Uint16.write('to client'); // write data to client to Uint16
Float32.write('to client'); // write data to client to Float32
//
// piping data to Float32
//
fs.createReadSteam(__dirname + '/example.js').pipe(Float32, {
end: false
});
//
// To stop receiving data, simply end the substream:
//
Uint16.end();
});
// client side:
var primus
, Uint8
, Uint16
, Float32
;
primus = new Primus('server address');
Uint8 = primus.substream('Uint8');
Uint8.write('to server'); // write data to server to Uint8
Uint16 = primus.substream('Uint16');
Uint16.write('to server'); // write data to server to Uint16
Float32 = primus.substream('Float32');
Float32.write('to server'); // write data to server to Float32
Uint8.on('data', function (data) {
console.log(data); // you get data from server to Uint8 ('to client')
});
Uint16.on('data', function (data) {
console.log(data); // you get data from server to Uint8 ('to client')
});
Float32.on('data', function (data) {
console.log(data); // you get data from server to Uint8 ('to client')
});
The above was taken from their documentation and changed to fit your example - i did not test it but it should work.
I hope that help.

Reassemble udp messages with node.js

I'm just getting started with node.js and UDP. I'm trying to capture UDP packets and then format the output.
The UDP packet's I'm receiving are being split up in to multiple messages. I can't figure out how to reassemble the message. I can concatenate each message, but how do I know that the message is complete? I need to process that data but I need to complete message.
FYI... This is for a scoreboard type application. The statistics are being broadcast via UDP and I'm trying to create an application that will monitor the stats.
Here is some basic code
var dgram = require("dgram");
var server = dgram.createSocket("udp4");
var fs = require('fs');
var STATS;
server.on("message", function (msg, rinfo) {
STATS = STATS + msg;
msg = msg + '<!>';
console.log(msg);
});
// *****************************
// When the message is complete
// Process STATS
// *****************************
server.on("listening", function () {
var address = server.address();
console.log("server listening " +
address.address + ":" + address.port);
});
server.bind(10101);
// server listening 0.0.0.0:41234
Do you have control over the client? If so, you can simply have some sort of symbol that identifies the end of a message, and your program can detect if msg ends with that.
But UDP sockets are volatile - there is no guarantee that any message will actually arrive. There is also no guarantee that your datagrams will arrive in the order that you send them. Correcting for these issues is more complex - if you don't need the real-time requirement, then switching to TCP is much easier.
TCP will automatically split your data into chunks when you send it from the client, so you will need to use that same end-of-message system, or detect when the socket is closed.

Why Won't the WebSocket.onmessage Event Fire?

After toying around with this for hours, I simply cannot find a solution. I'm working on a WebSocket server using "node.js" for a canvas based online game I'm developing. My game can connect to the server just fine, it accepts the handshake and can even send messages to the server. However, when the server responds to the client, the client doesn't get the message. No errors, nothing, it just sits there peacefully. I've ripped apart my code, trying everything I could think of to fix this, but alas, nothing.
Here's a stripped copy of my server code. As I said before, the handshake works fine, the server receives data fine, but sending data back to the client does not.
var sys = require('sys'),
net = require('net');
var server = net.createServer(function (stream) {
stream.setEncoding('utf8');
var shaken = 0;
stream.addListener('connect', function () {
sys.puts("New connection from: "+stream.remoteAddress);
});
stream.addListener('data', function (data) {
if (!shaken) {
sys.puts("Handshaking...");
//Send handshake:
stream.write(
"HTTP/1.1 101 Web Socket Protocol Handshake\r\n"+
"Upgrade: WebSocket\r\n"+
"Connection: Upgrade\r\n"+
"WebSocket-Origin: http://192.168.1.113\r\n"+
"WebSocket-Location: ws://192.168.1.71:7070/\r\n\r\n");
shaken=1;
sys.puts("Handshaking complete.");
}
else {
//Message received, respond with 'testMessage'
var d = "testMessage";
var m = '\u0000' + d + '\uffff';
sys.puts("Sending '"+m+"' to client");
var result = stream.write(m, "utf8");
/*
Result is equal to true, meaning that it pushed the data out.
Why isn't the client seeing it?!?
*/
}
});
stream.addListener('end', function () {
sys.puts("Connection closed!");
stream.end();
});
});
server.listen(7070);
sys.puts("Server Started!");
Here's my client side code. It uses Chrome native WebSockets.
socket = new WebSocket("ws://192.168.1.71:7070");
socket.onopen = function(evt) {
socket.send("blah");
alert("Connected!");
};
socket.onmessage = function(evt) {
alert(evt.data);
};
var m = '\u0000' + d + '\uffff';
var result = stream.write(m, "utf8");
Ah, that seems not quite right. It should be a zero byte, followed by a UTF-8 encoded string, followed by a 0xFF byte.
\uFFFF does not encode in UTF-8 to a 0xFF byte: you get 0xC3 0xBF. In fact no character will ever produce an 0xFF in UTF-8 encoding: that's why it was picked as a terminator in WebSocket.
I'm not familiar with node.js, but I would guess you'd need to say something like:
stream.write('\u0000'+d, 'utf-8');
stream.write('\xFF', 'binary');
Or manually UTF-8 encode and send as binary.
The handshaking is also questionable, though I guess it's a simple-as-possible first draft that's probably working for you at the moment. You're relying on the first packet being the whole handshake header and nothing else, then the second packet being the payload data. This isn't at all guaranteed. You'll probably want to collect data in a buffer until you see the 0x0D 0x0A 0x0D 0x0A marker for the end of the headers, then check the header content and possibly return the 101, then continue from data after that marker.

Categories

Resources