I am doing an interactive game with a Raspberry Pi and Sockets and I emit with a high rate (1-20 per second per listener) from the RPI to the server that's on the laptop.
At some times everything is ok but other times it gets really buggy (taking a few ms to display changes).
Is there a way to optimize this communication with Socket.IO or are there any alternative ways on doing this?
P.S. I'm doing plain emits with no data to be lighter.
EDIT:
Server:
socket.on('player1', function(){
//doing calculations
});
socket.on('player2', function(){
//doing calculations
});
socket.on('player3', function(){
//doing calculations
});
Client:
socket.emit('player1');
socket.emit('player2');
socket.emit('player3');
EDIT 2
These are the "calculations" that I am doing when I receive an emit from the Pi, it's some very basic RaphaelJS object animations.
var pos = this.objects[index].getPointAtLength(this.counter[index]);
this.e[index].attr({
x: pos.x,
y: pos.y
});
this.counter[index]++;
Related
Right part of my code is
io.sockets.on('connection', function(socket){
var interval = setInterval(function() {
repaintGraph()
socket.emit('set data chart', '{"series":[['+series+']]}');
}, 1000 );
The chart in this case, if I have 3 users connected, the chart updates 3 times in one second I need to execute the code 1 time in 1 second, regardless of the number of clients
You can run the interval code outside of the connection code:
setInterval(function() {
repaintGraph();
io.emit('set data chart', '{"series":[['+series+']]}');
}, 1000);
io.on('connection', function() {
...
});
io.emit() will broadcast the message to all connected clients, every second.
There's a little bit of an inefficiency in the code, in that it will call repaintGraph() every second even if there aren't any clients connected, but it makes the code much easier.
try to use
socket.broadcast.emit('event',data)
I am trying to receive and send data from a vacuum gauge (previous Model of https://www.pfeiffer-vacuum.com/en/products/measurement/digiline/gauges/?detailPdoId=13238&request_locale=en_US) with a computer (Linux 16.04) via an USB-to-RS485-Interface (the half-duplex USB485-STISO from http://www.hjelmslund.dk/). When I send a request to the gauge using a specific protocol it is supposed to answer to the request and I should be able to receive it with the interface. I managed to send data but whenever I send data, it seems that nothing comes back. I'm trying to do this with Node.js. The Code that I used so far is:
function pack(address, action, parameter, data) {
var length = String('00' + data.length.toString()).slice(-2);
var bufferAsString = address + action + parameter + length + data;
var check = 0;
for (var i = 0; i < bufferAsString.length; ++i) {
check += bufferAsString.charCodeAt(i)
}
var checkSum = String('000' + String(check % 256)).slice(-3);
var buffer = Buffer.from(bufferAsString + checkSum),
carriageReturn = Buffer.from('\r');
return Buffer.concat([buffer, carriageReturn]);
}
var serialPort = require('serialport');
var SerialPort = serialPort.SerialPort;
var port = new SerialPort('/dev/ttyUSB0', {
baudrate: 9600,
dataBits: 8,
stopBits: 1,
parity: 'none'
}, false);
port.open(function(err) {
if (err) {
return console.log('Error opening port: ', err.message);
}
console.log(port.isOpen());
port.on('data', function (data) {
console.log('Data: ' + data);
});
port.on('close', function() {
console.log('port closed')
});
var sendBuffer = pack('001', '00', '740', '=?');
setInterval(function() {
port.write(sendBuffer, function(err, bytes) {
console.log('send' + bytes)
});
port.drain();
}, 1000)
});
That is supposed to send a request every second to the gauge to measure the pressure. I know that the request is being send since the TxD-Led blinks shortly every second. But I receive no answer to that request.
I also tried other methods of sending data (mostly via python and the terminal) but with similar success. The green lamp for sending always flashes up but then nothing happens and no answer is received.
I am at a loss as to what to try next and would really appreciate any help that you could give me.
UPDATE:
Ok so I seem to have found one possible error in the whole thing. I was working with an oszilloscope to capture the signal that is going out of the interface when I send something. I started with single ascii-characters to see if the most basic signals are cominng out right. For ascii '0' the signal that is being sent is 10000011001, for ascii '1' it is 10100011001. So those are almost what I would expect, except that there seem to be 2 startbits. Normally I would expect there to be only 1 startbit. Is there a way to change the amount of startbits sent?
Here are the outputs of the Oszilloscope:
this is a communication problem:
1 check the protocol-based communications parameters like baud rate, parity, start-/stop-bits they have to be consistent
(if you use UART protocol on RS-485 other protocols like MODBUS, Profibus,... are also possible, this is a difference to normal RS-232)
If the gauge uses 9600 baud for communication you can not use 115200 baud in your command. In the nodejs code you do not set any parameter (i assume you use the UART protocol because of your nodejs). If the gauge uses any other protocol the nodejs code will also not work, despite that there are not set any parameters like baud rate, parity,... in the code
https://en.wikipedia.org/wiki/RS-485
for other protocols node js serial module can not be used
http://libmodbus.org/
http://www.pbmaster.org/
2 check the proprietary commands you send to the gauge. When i want to read out the data of my multimeter i have to send an ASCII 'D' = 0100 0100 (bin) to get an answer (endianness ?) If i send any other value the multimeter stays silent.
http://electronicdesign.com/what-s-difference-between/what-s-difference-between-rs-232-and-rs-485-serial-interfaces
Unless you have DE pulled high and R︦E︦ tied to ground, your conversation will be rather one-sided.
And if you do wire as above, you need to be able to deal with your own echo in the received data.
to many this may be an easy question but I'm trying to figure out the reason/logistics as to how socketIO handles variables. In the following code, x is set to 0, every second it counts up. Now if you had 1000 clients connected, every time the connect would each client get a new count starting at 0 and not affect every other connected client?
Also, is there a way to emit a new number to ever connected client instead of each connected client? Thanks!
io.sockets.on('connection', function (socket) {
x= 0;
var socketSend = setInterval(function(){
x = x+1;
socket.emit('count', { number: x });
}, 1000);
});
the socketSend is visible only to inside the callback of connection event, so every time a client connects the callback is called, passing along the socket object, so every client will get 0 as a start and the count will begin.
I'm working on an Arduino project to control motors and read sensors. I decided to use the web view using Node.js as a medium channel to read/write from the serial port to the browser using either libraries (SerialPort and SerialPort2).
Both are working fine when I connect the Arduino directly to the USB device using a wire, but Node.js can't seem to read anything when I connect the Arduino to the USB device through my wireless adapter** (APC220) even though I can read everything received on it using the Arduino serial monitor.
I checked every possible reason behind that; I checked the baud-rate I'm using for the Arduino communication with the wirelss serial and the APC220 and the bridge connector (USB-to-serial converter). They all have the same settings: 9600 baud-rate, no parity /flowcontrol, data bits: 8 , stop bits: 1.
The behavior is as follows. It connects to the COM port without trouble, and then I tried printing the errors, but it seems there are none identified by either SerialPort libraries. Then no reading comes to the event (data), which means it (Node.js) is not interacting with the serialport even though it is open.
Note:
I know I can use another Arduino as a medium between the USB port and the wireless adapter, but I want to understand this problem and solve it cleanly without such work around.
What could the problem be?
server [node.js]:
var SerialPort = require('serialport2').SerialPort;
var portName = 'COM15';
var io = require('socket.io').listen(8000); // Server listens for socket.io communication at port 8000
io.set('log level', 1); // Disables debugging. This is optional. You may remove it if desired.
var sp = new SerialPort(); // Instantiate the serial port.
sp.open(portName, { // portName is instatiated to be COM3, replace as necessary
baudRate: 9600, // This is synchronised to what was set for the Arduino code
dataBits: 8, // This is the default for Arduino serial communication
parity: 'none', // This is the default for Arduino serial communication
stopBits: 1, // This is the default for Arduino serial communication
flowControl: false // This is the default for Arduino serial communication
});
io.sockets.on('connection', function (socket) {
// If socket.io receives message from the client browser then
// this call back will be executed.
socket.on('message', function (msg) {
console.log(msg);
});
// If a web browser disconnects from Socket.IO then this callback is called.
socket.on('disconnect', function () {
console.log('disconnected');
});
});
var cleanData = ''; // This stores the clean data
var readData = ''; // This stores the buffer
sp.on('data', function (data) { // Call back when data is received
readData = data.toString(); // Append data to buffer.
// If the letters '[' and ']' are found on the buffer then isolate what's in the middle
// as clean data. Then clear the buffer.
console.log(readData); // **Here you should be able to print the data if you receive any**
if (readData.indexOf(']') >= 0 && readData.indexOf('[') >= 0) {
cleanData = readData.substring(readData.indexOf('[') + 1, readData.indexOf(']'));
readData = '';
console.log("-- "+cleanData);
io.sockets.emit('message', cleanData);
}else if(readData.indexOf('[') >= 0){
cleanData = readData.substring(readData.indexOf('[') + 1, readData.length);
readData = '';
}else if(readData.indexOf(']') >= 0){
cleanData += readData.substring(0, readData.indexOf(']'));
readData = '';
console.log("-- "+cleanData);
io.sockets.emit('message', cleanData);
}else{
cleanData += readData;
readData = '';
}
//console.log(readData);
//io.sockets.emit('message', readData);
});
While the monitor is running no other program can read the serial port.
In case you do not open both at the same time then things are more tricky. My suggestion would be to spy on the wire. That is: install Wireshark and have a look at the data on the serial connection / USB bus.
You might also want to check how the serial port of the APC220 and the Arduino differ with regard to their serial/USB converters. Another idea would be to analyze this issue under Linux since may allow more insights into the low-level differences of the chip sets / USB activity. Of course if you do not have Linux experience this is hard to do, but maybe you know some Linux enthusiasts.
Well, both your codes look all right, so I'm pretty sure your problem is something obvious (like the nose in the middle of your face) that you don't see because you're too focused on details. So here's a checklist I'd do first:
Are you sure your serial interface is the COM15, and never changes?
Are you sure both APC devices have correct baudrate configured?
Did you try making your Arduino send a simple code that sends the same thing over the channel?
Like:
void loop() {
...println("TEST");
delay(1000);
}
And on your host:
sp.on('data', function (data) {
console.log(data.toString());
});
When you get something buggy in your system, try to build the most simple use case of that buggy part, so you're sure that's nothing else in your codes that interferes with that. You don't need to make your Arduino work on the GPS stuff, as well as your Node.js stuff work on the web stuff.
Just make it the most simple as you can. (And don't forget to add a delay in your Arduino loop, or you may have difficulties reflashing the chip).
You may also want to add to your code the error catching part of serialport2:
port.on('error', function(err) {
console.log("ERROR receiving serial data: ", err);
});
As well as for your open() statement:
sp.open(portName, portConfig, function (err) {
console.log("ERROR opening serial port: ", err);
});
As you may be missing error reporting on the host side!
I'm making simple online game which based on Web.
the game uses Socket.io for netwoking each other.
but I encountered the problem.
think about following situation .
I ran Socket.io server.
one player making the room , and other player join the room.
they played game some time ..
but one player so angry and close the game tab.
in this situation , how can I get the event which one client have been closed the browser in server-side ?
according to googling , peoples say like this : "use browser-close event like onBeforeUnload"
but I know that All browser don't support onBeforeUnload event. so i want solution about
checking the client disconnection event in SERVER SIDE.
in Socket.io ( nodeJS ) server-side console , when client's connection closed , the console say like following :
debug - discarding transport
My nodeJS version is 0.4.10 and Socket.io version is 0.8.7. and both are running on Linux.
Anyone can help please ?
shortend codes are here :
var io = require ( "socket.io" ).listen ( 3335 );
io.sockets.on ( "connection" , function ( socket )
{
socket.on ( "req_create_room" , function ( roomId )
{
var socketInstance = io
.of ( "/" + roomId )
.on ( "connection" , function ( sock )
{
sock.on ( "disconnect" , function ()
{
// i want this socket data always displayed...
// but first-connected-client doesn't fire this event ..
console.log ( sock );
}
});
});
});
Update: I created a blog post for this solution. Any feedback is welcome!
I recommend using the 'sync disconnect on unload' option for Socket IO. I was having similar problems, and this really helped me out.
On the client:
var socket = io.connect(<your_url>, {
'sync disconnect on unload': true });
No need to wire in any unload or beforeunload events. Tried this out in several browsers, and its worked perfectly so far.
There's an event disconnect which fires whenever a socket.io connection dies (note that you need this, because you may still have a wep page open, but what if your internet connection dies?). Try this:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function () {
io.sockets.emit('user disconnected');
});
});
at your server. Taken from Socket.IO website.
//EDIT
So I looked at your code and did some tests at my place. I obtained the very same results as you and here's my explanation. You are trying to make Socket.IO very dynamic by dynamically forcing it to listen to different urls (which are added at runtime). But when the first connection is made, at that moment the server does not listen to the other url. It seems that exactly at that point (when connection is accepted) the disconnect handler is set for the first connection and it is not updated later (note that Socket.IO does not create new connections when you call io.connect many times at the client side). All in all this seems to be a bug! Or perhaps there is some fancy explanation why this behaviour should be as it is but I do not know it.
Let me tell you some other things. First of all this dynamical creation of listeners does not seem to be a good way. In my opinion you should do the following: store the existing rooms and use one url for all of them. Hold the ID of a room and when you emit for example message event from client add the ID of a room to the data and handle this with one message handler at the server. I think you get the idea. Push the dynamic part into the data, not urls. But I might be wrong, at least that's my opinion.
Another thing is that the code you wrote seems to be bad. Note that running .on('connection', handler) many times will make it fire many times. Handlers stack one onto another, they do not replace each other. So this is how I would implement this:
var io = require("socket.io").listen(app);
var roomIds = [];
function update_listeners(id) {
io.of("/"+id).on("connection", function(socket) {
console.log("I'm in room " + id);
socket.on("disconnect", function(s) {
console.log("Disconnected from " + roomId);
});
});
}
var test = io.sockets.on("connection", function(socket) {
console.log("I'm in global connection handler");
socket.on("req_create_room", function(data) {
if (roomIds.indexOf(data.roomId) == -1 ) {
roomIds.push(data.roomId);
update_listeners(data.roomId);
}
test.emit("room_created", {ok:true});
});
socket.on("disconnect", function(s) {
console.log("Disconnected from global handler");
});
});
Keep in mind that the problem with creating connections before the listeners are defined will still occure.