Raising socket events from from nodejs code - node.js

I am using net library in node. I want to raise a close event from my code. Is there any way i can do that?
If socket object is stored, I can perform sock.destroy() on it but the client will not be informed about the closing connection, which results in half dropped connection.
Is there any other way to handle this case ?

Emit to that specific socket (client) a custom 'kill_connection' event in order to inform the client about the connection being terminated for whatever reason you decided.
For example using socket.io :
var csid = socket.id; //The socket you are going to destroy
io.to(csid).emit('kill_connection');
Do this before performing the destruction of the socket.
Your client (if a webapp) could look something like:
socket.on("kill_connection", killSession);
function killSession(){
socket.disconnect();
console.log("socket.disconnect");
location.reload();
}
The reload is in case you want a single-page webapp to show the login screen.

Related

Uncaught TypeError: socket.to is not a function

I want to emit some data to a room in socket.io.
According to the socket.io docs,
In one place (https://socket.io/docs/rooms-and-namespaces/#Joining-and-leaving) it is said,
io.to('some room').emit('some event');
And in another place (https://socket.io/docs/emit-cheatsheet/) it is said,
socket.to('some room').emit('some event', "description");
I tried both of these but got the error,
uncaught TypeError: io.to is not a function
and
uncaught TypeError: socket.to is not a function
All other socket.io functions i used worked except for this
I included
<script src="/socket.io/socket.io.js"></script>
in the head tag of the html file.
In the client side js file, i incuded
const socket = io.connect("http://localhost:3000/");
Also, I used socket.emit and it works the way it is supposed to.
Please tell me what is wrong with this..
If this Uncaught TypeError is happening on your client side, that's because io.to and socket.to are only server-side functions, and cannot be used on the client side. In the Client API part of the Socket.IO docs, it doesn't specify io.to and socket.to as valid API functions. Here is the client API docs.
And here is a snippet that you can use to emit to Socket.IO rooms:
Server
//Your code...
io.on("connection", socket => {
//Don't forget to do this!
socket.join("some room");
socket.on("some event", data => {
//Do socket.to if you want to emit to all clients
//except sender
socket.to("some room").emit("some event", data);
//Do io.to if you want to emit to all clients
//including sender
io.to("some room").emit("some event", data);
});
});
Client
//Remember to include socket.io.js file!
const socket = io.connect("http://localhost:3000");
socket.on("some event", data => { /* Whatever you want to do */ });
//To emit "some event"
//This will also emit to all clients in the room because of the way the server
//is set up
socket.emit("some event", "description");
If you need an explanation...
So what this does is, basically, since you can't emit to rooms on the client side (you can only emit to server), the client emits to the server, and the server emits the event to the room you want to emit to.
Hope this solves your problem :)
Step1: In the client-side js file, changes instead of io.connect("http://localhost:3000/") use given below line,
let io = require('socket.io').listen(server.listener);
Step2: You need to create a connection in (Both Client & serverSide) For the Testing purpose you can use check connection Establish or not Both End use can use Socket.io tester Chrome Extension.(https://chrome.google.com/webstore/detail/socketio-tester/cgmimdpepcncnjgclhnhghdooepibakm?hl=en)
step3: when a socket connection is Established in Both ends then you emit and listen to data Easily.
One thing when you listen to the data then sends Acknowledgement using Callback Function. I have Received data Successfully.
E.g.`
socket.on('sendMessage',async (chatdata,ack)=>{
ack(chatdata);
socket.to(receiverSocketId).emit('receiveMessage',chatdata);
});
`
yours, emitting a message is correct no need to change this one. But make sure and please check it again your socket connection is Establish successfully or not. another Shortcut way you can debug a code line by line you can easily resolve this problem.
I Hope using this approach you can resolve the Error, and it is help For a Future.
thanks:)

socket.emit within collection.find.each problem [duplicate]

So, I am still in the experimental phase of Socket.io, but I just can't figure out why my code is doing this. So, I have the code below and when I console.log the code, it repeats the the connection even when there is only one connection. Do you know a solution?
io.on('connnection', (socket) => {
console.log("A new user is connected.")
})
Client side:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io()
</script>
Node.js Console:
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
...
(Note: there is only one connection, and I have already cleared the browser cashe)
Here are some of the possible reasons for socket.io connecting over and over:
Your socket.io client and server versions do not match and this causes a connection failure and an immediate retry.
You are running with some infrastructure (like a proxy or load balancer) that is not configured properly to allow lasting webSocket connections.
You are running a clustered server without sticky webSocket connections.
You have put the server-side io.on('connnection', ...) code inside some other function that is called more than once causing you to register multiple event handlers for the same event so you think you're getting multiple events, but actually you just have multiple listeners for the one occurrence of the event.
Your client code is calling its var socket = io() more than once.
Your client page is reloading (and thus restarting the connection on each reload) either because of a form post or for some other reason.
FYI, you can sometimes learn something useful by installing listeners for all the possible error-related events on both client and server connections and then logging which ones occur and any parameters that they offer. You can see all the client-related error events you can listen to and log here.
To solve repetion problem write your code like that for socket:
io.off("connnection").on('connnection', (socket) => {
console.log("A new user is connected.")
})

socketIO handshake behavior when connecting to different namespaces

I am having troubles with socketIO (nodejs) and using multiple namespaces. Maybe I misunderstood how to use it, but this is how I understood it should work.
Server side (nodejs)
io.of('/game').on('connection', socket => {
console.log(socket.handshake.query);
console.log('user connected to game socket', socket.id);
})
io.of('/api').on('connection',socket => {
console.log(socket.handshake.query);
console.log('user connected to api socket', socket.id);
}
Client side (browser)
function test (){
gameSocketTest = io.connect('http://localhost:4003/game',{query:{test:'test'}});
apiSocketTest = io.connect('http://localhost:4003/api');
}
The weird thing is that the query (that I only send to the "game" namespace) arrives in both handlers, also the one of the api.
If I inverse the order of the client side code to:
function test (){
apiSocketTest = io.connect('http://localhost:4003/api');
gameSocketTest = io.connect('http://localhost:4003/game',{query:{test:'test'}});
}
the query in the handshake is empty in both handlers server side. So my conclusion is that one way or another the same handshake is used for both connections (however the socket ids are different for both).
Is it "uberhaupt" possible to do what I am trying to do? If so, what am I not understanding with this weird handshake behavior.
In my understanding calling on the client side "io.connect()" should create 2 separate socket io clients, each with their own handshake.
Thanks for any help!
Andries
You must open new connection explicitly as Socket.IO tries to be smart and re-use connections (which causes a lot of connection issues actually) The way around this is use the force new connection option in your io.connect
gameSocketTest = io.connect('http://localhost:4003/game',{query:{test:'test'}});
apiSocketTest = io.connect('http://localhost:4003/api', {'force new connection': true});
From docs
When called, it creates a new Manager for the given URL, and attempts
to reuse an existing Manager for subsequent calls, unless the
multiplex option is passed with false. Passing this option is the equivalent of passing 'force new connection': true

What's the correct way to pass a Socket.IO socket between modules?

At the moment I have a getter/setter socket module as follows
var socket;
module.exports.getSocket = getSocket;
module.exports.setSocket = setSocket;
function getSocket() {
return socket;
}
function setSocket(sock) {
if (undefined == socket) socket = sock;
}
In app.js I set as follows
var sio = require('./lib/socket');
var io = require('socket.io').listen(app);
io.sockets.on('connection', function (socket) {
sio.setSocket(socket);
});
In my module I use as follows
sio = require('./lib/socket');
socket.getSocket().broadcast.emit(...);
It seems a bit contrived is there a better way to do this?
Edit: I would like a general solution to the problem of firing off a message which is not initiated by the client socket. For example suppose I retrieve stock prices from an external source and wish to fire an event on price update. Since it is not client initiated, how can I get access to the socket? Or alternatively let's say I wish to fire off a socket message in response to a POST request. Once again I'm not sure how I would access the socket.
There are a number of options for sharing the socket, but it would help to know more about what your module is going to do. Without knowing more, I would recommend you just pass the socket to the module via the function you are calling instead of trying to use some shared state.
If you need to use a shared state (you're trying to send messages to specific users triggered by something other than a socket message) then I would recommend sticking with an established session framework and just persist the socket id. You can get the correct socket just using the id.
See this answer for how to use socket.io with sessions: socket.io and session?
Add some more details and I'll revise my answer.
UPDATE
If you are just trying to broadcast to everyone who is connected, you do not need a socket handle. From any module that references socket.io, you can call io.sockets.emit('stuff').

node.js + socket.io broadcast from server, rather than from a specific client?

I'm building a simple system like a realtime news feed, using node.js + socket.io.
Since this is a "read-only" system, clients connect and receive data, but clients never actually send any data of their own. The server generates the messages that needs to be sent to all clients, no client generates any messages; yet I do need to broadcast.
The documentation for socket.io's broadcast (end of page) says
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
So I currently capture the most recent client to connect, into a variable, then emit() to that socket and broadcast.emit() to that socket, such that this new client gets the new data and all the other clients. But it feels like the client's role here is nothing more than a workaround for what I thought socket.io already supported.
Is there a way to send data to all clients based on an event initiated by the server?
My current approach is roughly:
var socket;
io.sockets.on("connection", function (s) {
socket = s;
});
/* bunch of real logic, yadda yadda ... */
myServerSideNewsFeed.onNewEntry(function (msg) {
socket.emit("msg", { "msg" : msg });
socket.broadcast.emit("msg", { "msg" : msg });
});
Basically the events that cause data to require sending to the client are all server-side, not client-side.
Why not just do like below?
io.sockets.emit('hello',{msg:'abc'});
Since you are emitting events only server side, you should create a custom EventEmitter for your server.
var io = require('socket.io').listen(80);
events = require('events'),
serverEmitter = new events.EventEmitter();
io.sockets.on('connection', function (socket) {
// here you handle what happens on the 'newFeed' event
// which will be triggered by the server later on
serverEmitter.on('newFeed', function (data) {
// this message will be sent to all connected users
socket.emit(data);
});
});
// sometime in the future the server will emit one or more newFeed events
serverEmitter.emit('newFeed', data);
Note: newFeed is just an event example, you can have as many events as you like.
Important
The solution above is better also because in the future you might need to emit certain messages only to some clients, not all (thus need conditions). For something simpler (just emit a message to all clients no matter what), io.sockets.broadcast.emit() is a better fit indeed.

Resources