I'm running a simple node.js server on Amazon EC2 that is running socket.io for me. I'm working on a chrome extension that sends data between two clients. However, if I take the server offline, the clients don't attempt to reconnect automatically. I would like to implement this feature. When I do socket = io.connect("http://xxx.xxx.xxx.xxx:xxx") if it can't find the server at the specified IP address and port, how do I get it to fire an event that makes it go into a recursive loop until it can? Does something like this exist?
function connect() {
socket = io.connect("http://123.456.789.1011:1337");
socket.on('server_not_found', function() {
connect();
});
}
From the socket.io wiki it looks like there is a connect_failed event that you can listen to (https://github.com/LearnBoost/socket.io/wiki/Exposed-events). That event did not fire for me (see https://github.com/LearnBoost/socket.io-client/issues/375) but the error event will fire if the connection fails and you can check the connection status on the socket. You could try either and see what works better.
An example might look like:
function connect() {
var socket = io.connect("http://123.456.789.1011:1337"),
timer;
socket.on('error', function() {
// wait 5 seconds then try again
if (!socket.socket.connected) {
timer = window.setInterval(function() { connect() }, 5000);
}
});
socket.on('connect', function() {
// we've connected so clear the timer
window.clearInterval(timer);
});
}
Related
i have a simple js script that "try" to connect to listening server (SocketTest) as shown in the image below. It's really simple, just one line :
var exampleSocket = new WebSocket('ws://127.0.0.1:6601');
So, yes, it is connected but it stay in pending mode finishing by "failed: WebSocket opening handshake timed out"
Maybe i'm wrong somewhere but i don't see it... and it's really simple.
If someone got an idea....
Thanks in advance.
Without implementing open event do not expect any answer from the server :)
Try this:
const WebSocket = require('ws');
const ws = new WebSocket('ws://127.0.0.1:6601');
ws.on('open', function open() {
ws.send('something');
});
Edit: The nodejs tag fooled me I thought it is server side.
The same true on client side, you need to handle onopen event:
// Connection opened
exampleSocket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Listen for messages
exampleSocket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
I am attempting to build a node.js application on a Raspberry Pi which can communicate with a remote socket.io server.
The socket.io server quite simply writes to the console when a new connection is established and when an existing connection is closed.
The socket.io client works as expected when run in a browser.
However, when I run the client code from a Raspberry Pi it connects and immediately terminates. This does not allow me to perform any function such as emitting or receiving.
The on connect event is never fired.
var io = require('/usr/local/lib/node_modules/socket.io-client');
var serverUrl = 'http://remoteserver.com';
console.log('Connecting to ' + serverUrl);
var socket = io.connect(serverUrl);
socket.on('connect', function(socket) {
console.log('Connection established!');
console.log(socket.id);
socket.on('disconnect', function() {
console.log('Disconnected from server');
});
});
The code above will output:
Connecting to: http://remoteserver.com
On the server side, the output will show a new connection and eventually a timeout close.
Why is the client on connect event not firing? How can I persist this connection so that I can eventually send inputs to the server?
Remove the line:
socket.close();
from your code. You are closing the socket immediately. Remember that all the event handlers are asynchronous. They are non-blocking and will be called some time in the future. Meanwhile, the rest of your code runs to completion and thus your socket.close() is executed before your client has any chance to get any events (other than the disconnect event).
If you want to do some stuff and then close the socket, then you need to close the socket only from some event handler that indicates that your operation is complete and you are now done with the socket.
You only need to call socket.close() when you want to close the connection from the raspberry pi. Also, the socket.io-client documentation does not use the .connect method, but instead calls require('socket.io-client')(serverUrl)
var io = require('/usr/local/lib/node_modules/socket.io-client');
var serverUrl = 'http://remoteserver.com';
console.log('Connecting to ' + serverUrl);
var socket = io(serverUrl);
socket.on('connect', function(socket) {
console.log('Connection established!');
console.log(socket.id);
});
socket.on('disconnect', function() {
console.log('Disconnected from server');
});
//Removed the socket.close() line
Is it possible to terminate a websocket connection from server without closing the entire server? If it is then, how can I achieve it?
Note: I'm using NodeJS as back-end and 'ws' websocket module.
So because of some sort of omission in the documentation regarding ws.close() and ws.terminate() I think the solutions in provided answers won't close the sockets gracefully in some cases, thus keeping them hanging in the Event Loop.
Compare the next two methods of ws package:
ws.close():
Initializes close handshake, sending close frame to the peer and awaiting to receive close frame from the peer, after that sending FIN packet in attempt to perform a clean socket close. When answer received, the socket is destroyed. However, there is a closeTimeout that will destroy socket only as a worst case scenario, and it potentially could keep socket for additional 30 seconds, preventing the graceful exit with your custom timeout:
// ws/lib/WebSocket.js:21
const closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly.
ws.terminate():
Forcibly destroys the socket without closing frames or fin packets exchange, and does it instantly, without any timeout.
Hard shutdown
Considering all of the above, the "hard landing" scenario would be as follows:
wss.clients.forEach((socket) => {
// Soft close
socket.close();
process.nextTick(() => {
if ([socket.OPEN, socket.CLOSING].includes(socket.readyState)) {
// Socket still hangs, hard close
socket.terminate();
}
});
});
Soft shutdown
You can give your clients some time to respond, if you could allow yourself to wait for a while (but not 30 seconds):
// First sweep, soft close
wss.clients.forEach((socket) => {
socket.close();
});
setTimeout(() => {
// Second sweep, hard close
// for everyone who's left
wss.clients.forEach((socket) => {
if ([socket.OPEN, socket.CLOSING].includes(socket.readyState)) {
socket.terminate();
}
});
}, 10000);
Important: proper execution of close() method will emit 1000 close code for close event, while terminate() will signal abnormal close with 1006 (MDN WebSocket Close event).
If you want to kick ALL clients without closing the server you can do this:
for(const client of wss.clients)
{
client.close();
}
you can also filter wss.clients too if you want to look for one in particular. If you want to kick a client as part of the connection logic (i.e. it sends bad data etc), you can do this:
let WebSocketServer = require("ws").Server;
let wss = new WebSocketServer ({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.send('something');
ws.close(); // <- this closes the connection from the server
});
and with a basic client
"use strict";
const WebSocket = require("ws");
let ws = new WebSocket("ws://localhost:8080");
ws.onopen = () => {
console.log("opened");
};
ws.onmessage = (m) => {
console.log(m.data);
};
ws.onclose = () => {
console.log("closed");
};
you'll get:
d:/example/node client
opened
something
closed
According to the ws documentation, you need to call websocket.close() to terminate a connection.
let server = new WebSocketServer(options);
server.on('connection', ws => {
ws.close(); //terminate this connection
});
Just use ws.close() in this way.
var socketServer = new WebSocketServer();
socketServer.on('connection', function (ws) {
ws.close(); //Close connecton for connected client ws
});
If you use var client = net.createConnection() to create the socket you can use client.destroy() to destroy it.
With ws it should be:
var server = new WebSocketServer();
server.on('connection', function (socket) {
// Do something and then
socket.close(); //quit this connection
});
I'm doing an HTML5 Game using node.js and socket.io
I decided to host it on Heroku.
Heroku isn't allowing the use of WebSockets, so I have to setup xhr-polling instead. (Socket-io on Heroku)
io.configure( function() {
io.set( "transports", ["xhr-polling"] );
io.set( "polling duration", 10 );
} );
Before, I was using web-sockets only
io.set( "transports", ["websocket"] );
Now, when a client disconnect (close his window or refresh his page) the event "disconnect" isn't trigger immediatly on the server (it looks like it's waiting for the client heartbeat to time out).
client.on( "disconnect", onClientDisconnect );
If the client reloads, I get multiple connection events before disconnect is fired.
My problem is here.
Do you have any ideas, why xhr-polling doesn't fire the disconnect event ?
Is this a bad configuration of socket.io ?
Thanks.
It says here that you can configure the heartbeat. To properly configure it, you must adjust the heartbeat both on the server and the client side (which is given here).
Try lowering the heartbeat. It may solve your problem.
On other note, appfog seems to support websockets.
Just configure session auth and you can always know what client has connected. E.g.
io.set('authorization', function(handshakeData, ack) {
var cookies = require(...);
var signedCookies = parseCookies(cookies, secret);
sessionStore.get(signedCookies['connect.sid'], function(err, sessionData) {
handshakeData.session = sessionData || {};
handshakeData.sid = signedCookies['connect.sid'] || null;
ack(err, err ? false : true);
});
});
I'm running Socket.io multi-threaded with the native cluster functionality provided by Node.js v0.6.0 and later (with RedisStore).
For every new change in state, the server iterates over each connection and sends a message if appropriate. Note: this isn't "broadcasting" to all connections, it's comparing server data with data the client sent on connection to decide whether to send the server data to that particular client. Consider this code sample:
io.sockets.clients().forEach(function (socket) {
socket.get('subscription', function (err, message) {
if(message.someProperty === someServerData) {
socket.emit('position', someServerData);
}
});
This worked fine when there was only one process, but now, the client receives a message for each Node process (ie. if there are 8 Node process running, all clients receive the messages 8 times).
I understand why the issue arises, but I'm not sure of a fix. How can I assign a 1-to-1 relation from one process to only on client. Perhaps something using NODE_WORKER_ID of Cluster?
This previous SO question seems somewhat related, although I'm not sure it's helpful.
This seems like a pretty common request. Surely, I must be missing something?
So if I get this straight you need to emit custom events from the server. You can do that by creating your own custom EventEmitter and triggering events on that emitter, for example:
var io = require('socket.io').listen(80);
events = require('events'),
customEventEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'positionUpdate' event
// which will be triggered by the server later on
eventEmitter.on('positionUpdate', function (data) {
// here you have a function that checks if a condition between
// the socket connected and your data set as a param is met
if (condition(data,socket)) {
// send a message to each connected socket
// if the condition is met
socket.emit('the new position is...');
}
});
});
// sometime in the future the server will emit one or more positionUpdate events
customEventEmitter.emit('positionUpdate', data);
Another solution would be to have those users join the 'AWE150', so only they will receive updates for 'AWE150', like so:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
if (client_is_interested_in_AWE) { socket.join('AWE150'); }
io.sockets.in('AWE150').emit('new position here');
});
Resources:
http://spiritconsulting.com.ar/fedex/2010/11/events-with-jquery-nodejs-and-socket-io/