Is it possible to force all clients to update using socket.io? I've tried the following, but it doesn't seem to update other clients when a new client connects:
Serverside JavaScript:
I'm attempting to send a message to all clients, which contains the current number of connected users, it correctly sends the amount of users.... however the client itself doesn't seem to update until the page has been refreshed. I want this to happen is realtime.
var clients = 0;
io.sockets.on('connection', function (socket) {
++clients;
socket.emit('users_count', clients);
socket.on('disconnect', function () {
--clients;
});
});
Clientside JavaScript:
var socket = io.connect('http://localhost');
socket.on('connect', function(){
socket.on('users_count', function(data){
$('#client_count').text(data);
console.log("Connection");
});
});
It's not actually sending an update to the other clients at all, instead it's just emitting to the client that just connected (which is why you see the update when you first load)
// socket is the *current* socket of the client that just connected
socket.emit('users_count', clients);
Instead, you want to emit to all sockets
io.sockets.emit('users_count', clients);
Alternatively, you can use the broadcast function, which sends a message to everyone except the socket that starts it:
socket.broadcast.emit('users_count', clients);
I found that using socket.broadcast.emit() will only broadcast to the current "connection", but io.sockets.emit will broadcast to all the clients.
here the server is listening to "two connections", which are exactlly 2 socket namespaces
io.of('/namespace').on('connection', function(){
socket.broadcast.emit("hello");
});
io.of('/other namespace').on('connection',function(){/*...*/});
i have try to use io.sockets.emit() in one namespace but it was received by the client in the other namespace. however socket.broadcast.emit() will just broadcast the current socket namespace.
As of socket.io version 0.9, "emit" no longer worked for me, and I've been using "send"
Here's what I'm doing:
Server Side:
var num_of_clients = io.sockets.clients().length;
io.sockets.send(num_of_clients);
Client Side:
ws = io.connect...
ws.on('message', function(data)
{
var sampleAttributes = fullData.split(',');
if (sampleAttributes[0]=="NumberOfClients")
{
console.log("number of connected clients = "+sampleAttributes[1]);
}
});
You can follow this example for implementing your scenario.
You can let all of clients to join a common room for sending some updates.
Every socket can join room like this:
currentSocket.join("client-presence") //can be any name for room
Then you can have clients key in you sockets which contains multiple client's data(id and status) and if one client's status changes you can receive change event on socket like this:
socket.on('STATUS_CHANGE',emitClientsPresence(io,namespace,currentSocket); //event name should be same on client & server side for catching and emiting
and now you want all other clients to get updated, so you can do something like this:
emitClientsPresence => (io,namespace,currentSocket) {
io.of(namespace)
.to(client-presence)
.emit('STATUS_CHANGE', { id: "client 1", status: "changed status" });
}
This will emit STATUS_CHANGE event to all sockets that have joined "client-presence" room and then you can catch same event on client side and update other client's status.
According to this Broadcasting.
With nodejs server, you can use this:
io.emit('event_id', {your_property: 'your_property_field'});
Be sure to initialise websocket, for example:
var express = require('express');
var http = require('http');
var app = express();
var server = http.Server(app);
var io = require('socket.io')(server);
app.get('/', function (req, res) {
res.send('Hello World!');
io.emit('event_hello', {message: 'Hello Socket'});
});
server.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
In this case, when user reach your server, there will be "event_hello" broadcasted to all web-socket clients with a json object {message: 'Hello Socket'}.
Related
I'm trying some things with socket.io on NodeJS and I can't figure out how to trigger the the socket (only) from NodeJS.
Till now I was using socket.io by calling it from the front end but I wonder if is it possible to do the same thing I did on the front end but this time on the nodeJS part(server side).
My guess is it's not possible because is required a kind of connection(I like to call it a TCP connection,but I'm not sure if that's true or not) and without a second participant in the connection the socket won't work.That's my guess.
So what I'm doing now is :
app.js(server file)
...
const ioLib = require('./path/io.js')(io);
...
...
...
path/io.js(socket file)
module.exports = function(io){
io.on('connection', async function(socket) {
console.log('socket talks : a user connected');
...
...
});
module.exports.io = io;
}
And from an file.ejs file I do :
var socket = io("url");
So with this,let's call it schema,I do the following :
When I access that webpage the 'connection' event is triggered in the sockets.
My question is,and I'm trying to formulate it as simple as I can :
How can I do the same but without a webpage?Is it possible to trigger the sockets inside the NodeJS?
What do you think?
It is possible to connect a Socket.IO server from a stand alone Node.js application (does not really matter where it runs) rather than a web front-end, accessed via a web browser. In order to achieve this, you should use socket.io-client. An example client usage might be as follows:
// Node.js app: client.js
const io = require('socket.io-client');
const socket = io.connect('http://SERVER_IP:SERVER_PORT', {
reconnect: true
});
socket.on('connect', function (socket) {
console.log('Connected to the server!');
});
socket.emit('connected', 'Hi from the client side!');
In this case, your server side application should include something as follows:
// Node.js app: server.js
io.on('connection', function(socket) {
console.log('socket talks: a user connected');
// Print the message that comes from the socket client
socket.on('connected', function (msg) {
console.log(msg);
});
});
As you can see above, fundamentally, the architecture remains the same as server-client. Now, let's go one step further and put all those codes in a single js file, and see how it works:
// server/client together: crazy-socketapp.js
const io_server = require('socket.io').listen(3030);
io_server.sockets.on('connection', function (socket) {
console.log('A client is connected!');
socket.on('connected', function (msg) {
console.log(msg);
});
});
const io_client = require('socket.io-client');
const socket = io_client.connect('http://localhost:3030', {
reconnect: true
});
socket.on('connect', function (socket) {
console.log('Connected to the server!');
});
socket.emit('connected', 'Hi from the client side! ');
The output of the app:
> A client is connected!
> Connected to the server!
> Hi from the client side!
Hope this helps!
I've got the following setup (important bits only for brevity):
app.js
...
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
server.listen(port, function() {
console.log(`Server is listening on port: ${port}`);
});
io.on('connection', function (socket) {
console.log('connection');
});
const routes = require('./routes/index')(io, passport);
app.use('/', routes);
index.js (server)
router.get('/game/:id', isAuthenticated, (req, res) => {
if (req.id)
{
var game = Game.findOne({_id: req.id}, (err, obj) => {
io.on('getGameInfo', (socket) => {
io.emit('gameInfo', obj);
});
res.render('game', obj);
});
}
else
{
// Id not valid, do something
}
});
client:
const socket = io('http://localhost:3000');
socket.on('gameInfo', function(data) {
console.log(data);
}.bind(this));
socket.on('connect', () => {
socket.emit('getGameInfo');
});
So basically I want to emit a getGameInfo call once I know the client has connected, and the getGameInfo listener has been set up in the game route. But when I emit the getGameInfo from the client, the server callback isn't being hit. I'm not sure if I'm missing something obvious, or if this is a closure issue, or if I'm just having one of those days, or if I'm going about this entirely the wrong way.
There are multiple problems here. I'll start by showing the correct way to listen for an incoming socket.io message on the server:
io.on('connection', function (socket) {
// here's where you have a new socket and you can listen for messages
// on that socket
console.log('connection');
socket.on('gameInfo', (data) => {
socket.emit('gameInfo', obj);
});
});
Some of the issues:
On the server, you listen for messages via the socket object, not via the io object. So, you would typically add these event listeners in the io.on('connection', ...) handler because that's where you first see newly connected sockets.
You pretty much never want to add event listeners inside an Express route handler because that is called many times. In addition, at the moment the route handler is called, the browser has not yet received the page and will not yet be connected so even if this was an OK place to do stuff, the page is not yet connected anyway.
When you want to send a message back to just one connection, you send it with socket.emit(), not io.emit(). io.emit() broadcasts to all connected clients which I don't think is what you want.
I'd suggest you not overload the same message name for client and server to mean two different things as this can lead to confusion when reading code or if you ever share some code between client and server. You client is really sending a "getGameInfo" message and then your server responds with a "gameInfo" message that contains the gameInfo.
If, in a route handler, you want to .emit() to the socket from that page which it looks like you are trying to do, then you have to do some work to create a link between the session of the current page and the socket for that page. There are a number of ways to do that. If you're using any session middleware, you can record the socket in the session at the point the socket connects. Then, from your express routes, you can get that socket from the session object at any time.
If I have my express.js server set up as such:
var express = require('express');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var port = process.env.PORT || 8080;
server.listen(8080);
And elsewhere I have a io.on('connnect', function(socket){...}); , should I be putting emit/event listeners on that socket within the io.connect(...) callback, or on the io object?
My basic program flow is as follows:
Client socket emits get_new_number.
Server receives get_new_number from unique socket.
Based on that unique socket ID, it emits new_number
The client listens for new_number and logs the data within to the console when triggered.
On the server-side, for part 2, I believe that must be a within the io.on('connect'...) function, so I can access socket.id for use later :
io.on('connect', function(socket){
socket.on('get_new_number', function(){
console.log('server got request for new number.');
globalVarId = socket.id;
});
});
But from there, where should I emit a new number to that unique socket? Say I save the socket.id and then emit to only it, how can I do that? The below isn't working:
io.on('connect', function(socket){
//get_new_number stuff
socket.to(globalVarId).emit('new_number', {number: someNumber});
});
Should I instead later do a io.to(globalVarId).emit... ?
EDIT: For that matter, is there a way to put event listeners on the io object, such like
io.on('someEvent', function(socket){
console.log('this socket did a thing, ', socket.id);
});
You can assume that socket within the callback function represents a unique client/connection.
So when you want to communicate with that client, you can use socket.emit():
io.on('connect', function(socket) {
socket.on('get_new_number', function() {
console.log('server got request for new number.');
//get_new_number stuff
socket.emit('new_number', { number: someNumber });
});
});
.to(...).emit(...) is used for something else entirely (sending a message to a particular room).
So I'm trying to broadcast Laravel 5 Events with the help of Redis. No I don't wanna use a service like Pusher since it's not free (even if the free limit would be enough for me) and I wanna keep control of the broadcast server.
So what I've done so far is, I'Ve set up a redis server (listening on port 6379 -> default), I've set up the following event:
class MyEventNameHere extends Event implements ShouldBroadcast
{
use SerializesModels;
public $data;
/**
* Create a new event instance.
*
* #return \App\Events\MyEventNameHere
*/
public function __construct()
{
$this->data = [
'power' => 10
];
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
return ['pmessage'];
}
}
I registered a route to that event:
Route::get('test',function()
{
event(new App\Events\MyEventNameHere());
return "event fired";
});
I've created (more like copied :P) the node socket server:
var app = require('http').createServer(handler);
var io = require('socket.io')(app, {origins:'*:*'});
var Redis = require('ioredis');
var redis = new Redis();
app.listen(6379, function() {
console.log('Server is running!');
});
function handler(req, res) {
res.writeHead(200);
res.end('');
}
io.on('connection', function(socket) {
console.log(socket);
});
redis.psubscribe('*', function(err, count) {
});
redis.on('pmessage', function(subscribed, channel, message) {
console.log(message);
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
And I created the view to actually receive the broadcast (testview.blade.php):
#extends('layout')
#section('content')
<p id="power">0</p>
<script>
var socket = io('http://localhost:6379');
socket.on("pmessage:App\\Events\\MyEventNameHere", function(message) {
console.log(message);
$('#power').text(message.data);
});
console.log(socket.connected);
</script>
#endsection
I can launch the redis server without any problems.
I can launch the node socket.js server and I'm getting the response "Server running"
When I hit the route to the event I get the return "event fired" in my browser.
When I hit the route to the actual view
Route::get('test/view',function()
{
return view('testview');
});
I can see the whole page (layout is rendered), and the webconsole does not show any errors.
However if I fire the event, the view won't change, which means, the broadcast is not received right?
Now I included an output for the console
console.log(socket.connected);
which should show me if the client is connected to the socket.io right?
Well, the output says false. What am I doing wrong here?
Further information on my setup: I'm running the whole project on the php built-in server, the whole thing is running on Windows (if ever that could matter), my firewall is not blocking any of the ports.
EDIT 1:
I forgot to say that my node server is not receiving the messages as well... It only says "Server running", nothing else.
EDIT 2:
I used another socket.js:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var Redis = require('ioredis');
var redis = new Redis();
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
redis.subscribe('test-channel', function () {
console.log('Redis: test-channel subscribed');
});
redis.on('message', function(channel, message) {
console.log('Redis: Message on ' + channel + ' received!');
console.log(message);
message = JSON.parse(message);
io.emit(channel, message.payload)
});
io.on('connection', function(socket) {
console.log('a user connected');
socket.on('disconnect', function() {
console.log('user disconnected');
});
});
http.listen(3000, function() {
console.log('listening on *:3000');
});
And this time the console receives the messages.
So if the node socket.io receives the messages, then what's wrong with my client? Obviously the messages are being broadcasted correctly, the only thing is that they are not being received by the client...
I can't say what is exactly wrong and probably no one can't, because your problem is to broad and enviroment dependent. Using Wireshark Sniffer you can easily determinate part of solution that is not working correctly and then try find solution around actual problem.
If your question is about how to do that, I will suggest not involving node on server side and use .NET or Java language.
The problem with your code is you are connecting your client socket to the redis default port 6379 rather than the node port that is 3000.
So in your blade view change var socket = io('http://localhost:6379'); to var socket = io('http://localhost:3000');
have you tried to listen to the laravel queue, from command line, before to fire the event?
php artisan queue:listen
I have two servers, one for the back end app, and one that serves the front end. They are abstracted, but share the same database, I have a need for both to communicate real time events between each other using socket.io.
Front end
// serves a front end website
var appPort = 9200;
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
socket.on('createRoom', function(room) {
socket.join(room); // use this to create a room for each socket (room) is from client side
});
socket.on('messageFromClient', function(data) {
console.log(data)
socket.broadcast.to(data.chatRoom).emit('messageFromServer', data);
});
});
Back end
//Serves a back end app
var appPort = 3100;
var express = require('express');
var app = express();
var http = require('http');
var server = http.createServer(app);
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
socket.on('createRoom', function(room) {
socket.join(room); // use this to create a room for each socket (room) is from client side
});
socket.on('messageFromClient', function(data) {
console.log(data)
socket.broadcast.to(data.chatRoom).emit('messageFromServer', data);
});
});
As an admin I want to log in to my back end where I can see all the people logged in, there I can click on whom I would like to chat with.
Say they are logged in to the front end website, when the admin submits a message client side they trigger this socket.emit('messageFromClient', Message); how can I trigger messageFromClient on the front end using port 9200 submitting from the backend port 3100?
You really dont need to start the socket.io server in the front end for this use case.
The way you can get it to work is :
Keep the backend as it is, which acts as a Socket.IO server
In the font end connect to the server using a Socket.IO client.
You can install the client by calling
npm install socket.io-client
and then connect to the server using :
var io = require('socket.io-client'),
socket = io.connect('localhost', {
port: 3100
});
socket.on('connect', function () { console.log("socket connected"); });
socket.emit('messageFromClient', { user: 'someuser1', msg: 'i am online' });
You can then create a map of socket objects with their corresponding username and send a message to that user based on your business logic.
More Information :
You may have to add cases like client disconnection etc. You can read more about the call backs for that here :
https://github.com/Automattic/socket.io-client