Why Won't the WebSocket.onmessage Event Fire? - javascript

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.

Related

How to connect to a TCP server and pass a Javascript to it

I'm definitely a newbie with JS and node. I have telescope management software called SkyX Pro, and it has the ability to run a TCP Server on port 3040. I can connect to it using Netcat and hand it a Javascript starting with //* Javascript *// this works and allows me to startup cameras and other equipment and send commands for taking pictures etc. The issue is it needs to be run from a batch file which makes getting any information back to an HTML page tough (Like Camera, focuser and filter wheel status and temperatures).
The NC call looks like "NC localhost 3040 < Javascript-file.js
To get around the browser to local machine security issues I want to run this from node.js with maybe socket.io-client if possible, but I don't know the proper syntax for it.
I have seen plenty of client syntax sending hello's etc. but nothing send javascript and allowing for two-way connectivity that I can understand.
I have tried using:
var socket = io.connect('http://localhost');`enter code here`
socket.on('httpServer', function (data) {
console.log(data);
document.write(data + "\r\n");
socket.emit('tcp', "For TCP");
});
const net = require('net');
const client = new net.Socket();
client.connect({ port: 3040, host: process.argv[2] });
client.on('data', (data) => {
console.log(data.toString('utf-8'));
But I do not understand it well enough to troubleshoot why it's not working.
Any help would be wonderful, and please treat me like a baby that needs its step by step.
Cheer
Peter
Reading [1], We can assume socket-io isn't the perfect fit for you, because that Server you have sound like a typical tcp-socket server, not a socket.io server ( which requires special headers ) or a web-socket server.
So you only needs "net" library to do the job.
const net = require('net');
// module to send a message to TCP-socket server and wait for the response from socket-server
const sendAndReceive = async (client, message) => {
client.write(message);
let response = null
await ( new Promise( (resolve, reject) => {
client.on('data', function(data) {
response = data;
resolve()
});
}))
return response;
}
// send a single message to the socket-server and print the response
const sendJSCode = (message) => {
// create socket-client
const client = new net.Socket();
client.connect(3040, 'localhost', async function() {
console.log('Connected');
// send message and receive response
const response = await sendAndReceive(client, message)
// parse and print repsonse string
const stringifiedResponse = Buffer.from(response).toString()
console.log('from server: ', stringifiedResponse)
// clean up connection
client.destroy()
});
}
sendJSCode('var Out; \n Out="TheSky Build=" + Application.build \n\r')
This script will:
Initiate a socket client
on connection successfully, client sends a message
client receives back response from that message
client prints response to terminal
Note that TheSkyX has a limitation of 4096 bytes for each message[2], any more than that and we will need to chunk the message. So you may want to keep the js-code short and precise.
that snippet I gave is minimal, it doesn't handle errors from server. If you want, you can add client.on("error", .. ) to handle it.
Your point of connecting to the socket server directly from browser is very intriguing, unfortunately it is not allowed by modern browsers natively due to security concerns 3
[1] https://socket.io/docs/#What-Socket-IO-is-not:~:text=That%20is%20why%20a%20WebSocket%20client,to%20a%20plain%20WebSocket%20server%20either.
[2] https://www.bisque.com/wp-content/scripttheskyx/scriptOverSocket.html#MSearchField:~:text=set%20to%204096%20bytes

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

Send CR LF in JavaScript string to node.js serialport server

I've successfully followed the instructions for creating a webpage to talk to serial ports found here. And here's the GitHub repository for his project. I've modified it slightly to use Windows COM ports and fake the Arduino data. Now I'm trying to modify it further to talk to one of my company's test boards. I've established two-way communication, so I know I can talk in both directions over the serial port.
Sending id?CRLF over serial to the board will get a response of something like id=91. I can do this in PuTTY by just typing in id? & hitting the Enter key, or in DockLight by creating a send sequence id?rn, both of which work as expected, I get the id=91 response.
However, in the client.js JavaScript, trying to send: socket.send("id?\r\n"); in the console doesn't work, but I see it show up with an extra line in the server response. So I see something like this:
Message received
id?
<=blank line
So I tried to send the ASCII equivalents by doing:
var id = String.fromCharCode(10,13);
socket.send("id?" + id);
Which also doesn't work, although two extra lines show up in the server.
Message received
id?
<=blank line
<=another blank line
EDIT: I've also tried: socket.send('id?\u000d\u000a'); Same results as the first Message received blurb above.
I see the sent command arrive at the server (I've modified it a bit to do a console.log upon receipt of a message from the client):
function openSocket(socket){
console.log('new user address: ' + socket.handshake.address);
// send something to the web client with the data:
socket.emit('message', 'Hello, ' + socket.handshake.address);
// this function runs if there's input from the client:
socket.on('message', function(data) {
console.log("Message received");
console.log(data);
//here's where the CRLF should get sent along with the id? command
myPort.write(data);// send the data to the serial device
});
// this function runs if there's input from the serialport:
myPort.on('data', function(data) {
//here's where I'm hoping to see the response from the board
console.log('message', data);
socket.emit('message', data); // send the data to the client
});
}
I'm not positive that the CRLF is the problem, but I'm pretty sure it is. Possibly it's being swallowed by the server?
How can I embed it in a string to be sent to the server so it get interpreted properly and sent along to the serial port?
Other SO pages I've read:
How can I insert new line/carriage returns into an element.textContent?
JavaScript string newline character?
Well, it turns out that the problem wasn't exactly the CRLF like I thought, it was how the string terminator was being handled. All of our devices use what we can an "S prompt" (s>) for when a command has been processed. When it's done the last thing the board does is return an S prompt, so I'd modified the original server parser code to look for that. However that's a response terminator, not a request terminator. Once I changed it back to parser: serialport.parsers.readline('\n') it started to work.
// serial port initialization:
var serialport = require('serialport'), // include the serialport library
SerialPort = serialport.SerialPort, // make a local instance of serial
portName = process.argv[2], // get the port name from the command line
portConfig = {
baudRate: 9600,
// call myPort.on('data') when a newline is received:
parser: serialport.parsers.readline('\n')
//changed from '\n' to 's>' and works.
//parser: serialport.parsers.readline('s>')
};

Writing and Parsing Binary Data in NodeJs

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!

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.

Categories

Resources