I have a very simple socket.io connection. My server does the following:
io.sockets.on("connection", function (socket) {
console.log("CONNECTED ON SERVER");
socket.emit("connected", "CONNECTED!");
});
Indeed, the client gets the "CONNECTED!" message.
I need to be able to detect when a client disconnects and take some action. I've tried:
io.sockets.on("disconnect", function (socket) {
console.log("DISCONNECTED!");
});
...but this does not log "DISCONNECTED!" on the server. However, CONNECTED ON SERVER from above does get logged.
I know that the socket can detect the disconnect because once I close the browser window, the server logs out:
info - transport end (socket end)
debug - set close timeout for client
debug - cleared close timeout for client
debug - cleared heartbeat interval for client
debug - discarding transport
This means that socket.io is able to detect that the client connection closed. How can I detect that it was closed?
You have to set the event on each socket itself
You can see on their how to use page they set the disconnect event on the actual socket:
// note, io.listen(<port>) will create a http server for you
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
io.sockets.emit('this', { will: 'be received by everyone'});
socket.on('private message', function (from, msg) {
console.log('I received a private message by ', from, ' saying ', msg);
});
socket.on('disconnect', function () {
io.sockets.emit('user disconnected');
});
});
If you take a look in the socket.io code (of at least v0.10.20) you will see that io.sockets is a SocketNamespace object (from namespace.js), and in that is the handlePacket function
the connection packet does
self.$emit('connection', socket);
Which will send the event to its own EventEmitter stuff.
Where as the disconnect packet is done this way:
socket.$emit('disconnect', packet.reason || 'packet');
So the disconnect event is never fired for the namespace object.
The current github code shows that they have moved the packet handling to their respective classes
connection emission in namespace.js Line 172
// fire user-set events
self.emit('connect', socket);
self.emit('connection', socket);
disconnect emission in socket.js Line 370
...
this.disconnected = true;
delete this.nsp.connected[this.id];
this.emit('disconnect', reason);
};
Related
I have this scenario with socket.io:
I want to receive the data from a sever and Forward the data to webclient.But when I receive a lot of data and close the page, it console
DISCONNECTED FROM CLIENT
DISCONNECTED FROM CLIENT
DISCONNECTED FROM CLIENT
DISCONNECTED FROM CLIENT
DISCONNECTED FROM CLIENT
DISCONNECTED FROM CLIENT
DISCONNECTED FROM CLIENT
...(a lot)
Here is the code:
server:
var express=require('express');
var app=express();
var net=require('net');
var http=require('http').createServer(app);
var io=require('socket.io')(http);
var net=require('net');
var nodeServer = new net.Socket();
var aSocket=null;
io.on('connection', function (socketIO) {
aSocket=socketIO;
};
nodeServer.on('data', function(data) {
if(aSocket!=null){
aSocket.emit('pushToWebClient',useData);
aSocket.on('disconnect', function () {
console.log('DISCONNECTED FROM CLIENT');
});
}
client:
socket.on('pushToWebClient', function (useData) {
});
I find
aSocket.on('disconnect', function () {
console.log('DISCONNECTED FROM CLIENT');
});
console a lot of'DISCONNECTED FROM CLIENT' but actually it should console just once in the code.
I had even console.log(aSocket.id),it console just only one.
I don't know why it is console so many times.
I haved used setMaxListeners(10) to try to avoid it .
Will it lead to a memory leak?
It appears that you are registering multiple event listeners for the same disconnect event. In this code:
nodeServer.on('data', function(data) {
if(aSocket!=null){
aSocket.emit('pushToWebClient',useData);
aSocket.on('disconnect', function () {
console.log('DISCONNECTED FROM CLIENT');
});
}
You appear to be registering a new disconnect event listener every time you get a data message. So, if you have multiple listeners, then each one will get called when the socket disconnects and the result is that you will log the same message multiple times all for the same socket.
You can verify this is what is happening by moving your disconnect handler into the connection handler so it is only ever attached just once for each socket.
In addition putting asocket into a global or module-level variable means that your server code would only ever work with one single client at a time. It is not clear exactly what you are trying to do when you get data on the nodeserver connection - whether you're trying to send that data to only one specific client or to all connected clients.
I try to delete the code:
aSocket.on('disconnect', function () {
console.log('DISCONNECTED FROM CLIENT');
});
or moving it out of nodeServer handler,
it turn into normal and never suggest me to setMaxlisener.
I think maybe it is incorrect put one API into a API
And the envent maybe not release the socket,so it console multiple times .
EDIT: I'm moving this to the top because I saw that someone already provided my solution but you were having a problem managing the data sent to the client. Your aSocket variable will be overwritten by every new client that connects to your app. If you want to send data to a specific client using your server nodeServer, you should create a global variable (an array) that keeps track of all of your client socket connections. So instead of using one global variable aSocket do the following:
var net=require('net');
var nodeServer = new net.Socket();
var clients = [];
io.on('connection', function (socketIO) {
clients.push(socketIO);
var clientNum = clients.length-1;
aSocket.on('disconnect', function () {
clients.splice(clientNum, 1);
console.log('DISCONNECTED FROM CLIENT: '+socketIO.id);
});
};
nodeServer.on('data', function(data) {
//have your data object contain an identifier for the client that caused the handler to fire
//for the sake of the answer I just use data.id
var clientID = data.id;
if(clients[clientID]!=null){
clients[clientID].emit('pushToWebClient', useData);
}
}
Let me know how it goes! My original answer is below:
Try moving
aSocket.on('disconnect', function () {
console.log('DISCONNECTED FROM CLIENT');
});
out of your nodeServer.on('data', ...) event listener into the io.on('connection', ...) event listener like so:
io.on('connection', function (socketIO) {
aSocket=socketIO;
aSocket.on('disconnect', function () {
console.log('DISCONNECTED FROM CLIENT');
});
};
socket.io is designed to keep polling for the presence of the server/client. If either the server or the client are disconnected, the remaining 'side' continues to receive polling requests and, consequently, will continuously print an error.
You can see this effect on the client side in your browser when you disconnect your server and leave the client page open. If you look at the browser's error/console log what you should see is a continuous stream of net::ERR_CONNECTION_REFUSED errors. By placing the disconnect event handler in the .on('data', ...) handler for your server, you are seeing the converse of this situation.
net:ERR_CONNECTION_REFUSED example
This is basic code for socket.io
The following example attaches socket.io to a plain Node.JS HTTP
server listening on port 3000.
var server = require('http').createServer();
var io = require('socket.io')(server);
io.on('connection', function(client){
client.on('event', function(data){});
client.on('disconnect', function(){});
});
server.listen(3000);
I think, you should try.
Am not able to call socket-client listener using sails.sockets.js onConnect event on server side..
E.g
onConnect: function(session, socket) {
socket.on('chat message', function(msg){
console.log(msg);
console.log("socket.id: " + socket.id);
sails.sockets.broadcast(socket.id, 'chat message', {msg:msg});
});
}
Please let me know whats the correct way of calling back to your socket-client using socket-server events like onConnect..
If you are using standard sails.js socket library:
$(document).ready(function() {
io.socket.on('connect', function() {
});
io.socket.on('chat message', function(data) {
io.socket.post('/routeToAction', {
}, function(data, jwres) {
});
});
});
for newer version, you have to use config/bootstrap.js file for listen events
module.exports.bootstrap = function(cb) {
// handle connect socket first event executes after logged in
sails.io.on('connect', function (socket){
// store facebook token here
});
// handle custom listener for other stuff
sails.io.on('doSomeStuff', function (socket){
// check facebook token match with requested token
});
cb();
};
client : you can simple emit "doSomeStuff" after logged in with facebook and pass token with each request
Finally am become little expert in web sockets who knows back anf forth of push technoligy via websockets..
How to start with websockets :
Step 1: Choose any websocket framework for your application and install socket client on client side and socker server on server side with listeners(imp.).
Step 2: Once you are ready with socket setup on both sides then your client/browser will make a connection after every page load which is listened on server side via onConnect listener or event.
Step 3: Successfull connection on both sides giving you socket object which contains each client socket id which is managed at server side to either join any channel/room or just to make a broadcast or blast.
Remember:
i. Socket object is responsible for defining listeners on both client side and server side. Using socket object you can pass any data to listeners.
ii. Socket connection is very helpful when you trying to push data from client to server and vice-versa.
iii. You can make your small chatter tool with it once you understand as mentioned above.
Will share similar working snippet soon..
//onConnect event on server side
onConnect: function(session, socket) {
console.log("Socket Connect Successfully: " + socket.id );
socket.on('chatAgency', function(data){
sails.sockets.broadcast(data.agencyId,"chatAgency", {message:data.message,agencyId:session.agencyId});
});
},
I have a very basic setup with socket.io but am having trouble getting my server to send back a message once the connection has been established.
When a connection is established to my server, I want the server to send back a message to the client. I've tried to accomplish this with the following code:
Server
// Modules
var fs = require('fs');
var https = require('https');
// Certificate
var options = {
pfx: fs.readFileSync('<my cert>')
};
// Create Server
httpsServer = https.createServer(options);
// Create websocket
var io = require('socket.io')(httpsServer);
// Listen on a port
httpsServer.listen(4000,function() {
console.log('listening on *:4000');
});
io.on('connection', function(socket) {
console.log('a user connected');
socket.emit('test','you connected');
});
Client
var socket = io('https://<my server>:4000');
When I execute this code, the websocket gets established and my server console shows the message "a user connected". However, the message ['test','you connected'] does not get emitted through the socket.
The only way I've been able to get this to work is to use setTimeout() to wait 500ms before emitting the event, in which case it does work.
Why is that? How can I configure my server to automatically respond with a message as soon as the user connects?
You need to listen to the emitted event, using socket.on(event, callback);
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script>
var socket = io('https://localhost:4000');
//test is the emitted event.
socket.on("test", function(data){
console.log(data); //"you connected"
});
</script>
Whenever I disconnect using socket.disconnect(); and then reconnect using socket.connect();, the server runs my handshake code twice. The strange thing is, even though the server connection code runs twice, there is only one connection in my array after reconnecting. This happens on an accidental disconnection, intentional, or even if the server restarts. Bit of code:
io.on('connection', OnConnect);
function OnConnect(socket) {
var connection = { socket: socket, realIp: ip, token: GenerateConnToken() };
connections.push(connection);
console.log('Connected');
// Client will respond to this by emitting "client-send-info".
// This is emitted once on initial connect, but twice on reconnect.
socket.emit('acknowledge', connection.token);
socket.on('client-send-info', function() {
console.log('Client Sent Info');
});
socket.on('disconnect', function() {
console.log('Disconnected');
});
}
The above code, when a client connects, disconnects, and then reconnects once, will produce the following log:
Connected
Client Sent Info
Disconnected
Connected
Client Sent Info
Client Sent Info
Why is it that, when reconnecting, the connection code will run twice, but only create one connection object?
EDIT: Upon further inspection, it seems that a different piece of my connection code is being performed twice when the client reconnects. The above code is updated to reflect the relevant information.
Strangely, the solution is completely client side. Instead of the following code:
var socket = io.connect();
socket.on('connect' function() {
socket.on('acknowledge', function() {
});
});
You have to use:
var socket = io.connect();
socket.on('connect' function() {
});
socket.on('acknowledge', function() {
});
Otherwise, the server will appear to be sending multiple emits when it is in reality only sending one, and it's the client that falsely receives multiples. With the second code format, the client successfully connects initially, disconnects, and reconnects without receiving multiple emits.
Simply, don't put any additional socket.on('x') calls inside the on('connection') call. Leave them all outside it.
Is there something that I can do on the client side to detect that the socket.io websocket is not available? Something along the lines of:
server starts as per usual
clients connect
messages are sent back and forth between server and client(s)
server shuts down (no longer available)
warn the connected clients that the server is not available
I tried to add the 'error' and 'connect_failed' options on the client side but without any luck, those didn't trigger at all. Any ideas from anyone how I can achieve this?
The disconnect event is what you want to listen on.
var socket = io.connect();
socket.on('connect', function () {
alert('Socket is connected.');
});
socket.on('disconnect', function () {
alert('Socket is disconnected.');
});
If you want to be able to detect that the client was not able to connect to the server, then try using connect_error. This works for me with socket.io-1.3.5.js. I found this in https://stackoverflow.com/a/28893421/2262092.
Here's my code snippet:
var socket = io.connect('http://<ip>:<port>', {
reconnection: false
});
socket.on('connect_error', function() {
console.log('Failed to connect to server');
});
hit this bug during my development and noticed my event calls were doubling up every time i reset the server, as my sockets reconnected. Turns out the solution that worked for me, which is not duping connections is this
var socket = io.connect();
socket.on('connect', function () {
console.log('User connected!');
});
socket.on('message', function(message) {
console.log(message);
});
( Found this at https://github.com/socketio/socket.io/issues/430 by KasperTidemann )
Turns out, it was becuase I put the 'message' listener inside the 'connect' function. Seating it outside of the listener, solves this problem.
Cheers to Kasper Tidemann, whereever you are.
Moving on!!
connect_error didn't work for me (using Apache ProxyPass and returns a 503).
If you need to detect an initial failed connection, you can do this.
var socket;
try {
socket = io();
}
catch(e) {
window.location = "nodeServerDown.php";
}
Redirects the user to a custom error page when the server is down.
If you need to handle a disconnect after you've connected once.
You do this:
socket.on('disconnect', function() {
//whatever your disconnect logic is
});