I'm trying to build an application that has two components. There's a public-facing component and an administrative component. Each component will be hosted on a different server, but the two will access the same database. I need to set up the administrative component to be able to send a message to the public-facing component to query the database and send the information to all the public clients.
What I can't figure out is how to set up a connection between the two components. I'm using the standard HTTP server setup provided by Socket.io.
In each server:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
app.listen(80);
function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
And on each client:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost');
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
I've looked at this question but couldn't really follow the answers provided, and I think the situation is somewhat different. I just need one of the servers to be able to send a message to the other server, and still send/receive messages to/from its own set of clients.
I'm brand new to Node (and thus, Socket), so some explanation would be incredibly helpful.
The easiest thing I could find to do is simply create a client connection between the servers using socket.io-client. In my situation, the admin server connects to the client server:
var client = require("socket.io-client");
var socket = client.connect("other_server_hostname");
Actions on the admin side can then send messages to the admin server, and the admin server can use this client connection to forward information to the client server.
On the client server, I created an on 'adminMessage' function and check for some other information to verify where the message came from like so:
io.sockets.on('connection', function (socket) {
socket.on('adminMessage', function (data) {
if(data.someIdentifyingData == "data") {
// DO STUFF
}
});
});
I had the same problem, but instead to use socket.io-client I decided to use a more simple approach (at least for me) using redis pub/sub, the result is pretty simple. My main problem with socket.io-client is that you'll need to know server hosts around you and connect to each one to send messages.
You can take a look at my solution here: https://github.com/alissonperez/scalable-socket-io-server
With this solution you can have how much process/servers you want (using auto-scaling solution), you just use redis as a way to forward your messages between your servers.
Related
I want to build a NodeJS API so that when I hit an endpoint, the app will trigger an event that will cause its unique socket connection to emit a message to its listeners. I have built a solution before using Python/Django, Redis, and NodeJS/Socket.io with Django as the API and Redis as the 'event trigger', but I would like to consolidate the different technologies into NodeJS and Socket.io.
I tried moving the socket.emit() code into different modules and then app.use()'d those modules, but the code broke because it didn't have an instance of the socket.
I also know that you can broadcast to all socket connections inside on an endpoint, for example:
app.use('socket.io/help', function(req, res) {
console.log(req.query);
io.sockets.emit('help_message', 'You should help me.');
res.send('help msg sent');
});
But I am looking for a way that allows a client (that doesn't have a socket connection) to hit an endpoint and pass a query param that tells NodeJS which of its connected sockets to send a message to.
Is this possible? Or am I trying to fight the framework? e.g., is there a different way of doing this with different JS WebSocket frameworks/technologies?
I have been stuck on same situation but resolved easily
you have created socket on app.js
server = require('http').createServer(app),
io = require('socket.io').listen(server);
server.listen(port);
global.socketIO = io;
Now you can call this io instance to your any controller like
app.use('socket.io/help', function(req, res) {
console.log(req.query);
var io = global.socketIO;
// UID IS THE VARIABLE
io.sockets.emit('help_message'+UID, 'You should help me.');
res.send('help msg sent');
});
CLIENT SIDE
<script src="/socket.io/socket.io.js"></script>
<script>
window.socket.on("help_message_<%-UID%>", function(msg){
//// ACTION
});
You can join a room with the specific sockets you want to recieve the messages on.
see Rooms & Namespaces in the socket.io documentation
join a chan on your helpdesk conenctions:
io.on('connection', function(socket){
socket.join('helpdesk');
});
and broadcast to them:
app.use('socket.io/help', function(req, res) {
console.log(req.query);
var io = global.socketIO;
io.sockets.emit('adduser', req.body.uid);
io.to('helpdesk').emit('some event'):
res.send('help msg sent');
});
when i try to communicate with my socket io, the connection is established and the websocket writing is taking place, but the hearbeat is not getting emitted on the server ..so im not receiving anything on the client side. but when i disconnect and connect the server again, the old written message is getting emitted. please help me through this. thank you
I have tried with different port numbers, but its not working.
app.js (Server):
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
server.listen(3000);
app.get('/', function(req, res){
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log("Connected");
});
});
index.html (Client)
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect();
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
</script>
Socket.io might work unstable because of firewall or antivirus. This is actually a problem of WebSockets.
To solve this you may try to exclude WebSockets from the transports between client and server and specify on server side just XHR long polling and JSONP (as these two are the most stable):
io.set('transports', ['xhr-polling', 'jsonp-polling']);
I would also recommend to take a look at Engine.io. This framework is written by Socket.io author as the alternative, which works more stable.
The trick is following:
While Socket.io tries to connect via WebSockets first (when this attempt is fail, user will have to wait about 10 sec to switch to another transport), Engine.io tries to connect via XHR (which works in 100% cases), and meanwhile tries WebSocket connection, and if success - switching to WebSockets occurs.
Edit: Socket.io version 1.0+ is built on the top of Engine.io, so it has now all the benefits described above.
I have problem with creating Azure Mobile Services Custom Script, I want to use Socket.IO Node.js module, but I don't know how to edit Azure Mobile Services route to be able to access /socket.io/1
After execution this code socket.io is started but client is not able to access URL endpoint from browser, please help me, thank you in advance, my email is: stepanic.matija#gmail.com
My code is:
in /api/notify
exports.register = function (api) {
api.get('socket.io',getSocketIO);
};
function getSocketIO(req,res)
{
var app = require('express')()
, server = require('http').createServer(app)
, io = require('socket.io').listen(server);
server.listen(80);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
res.send(statusCodes.OK, { message : '23 Hello World!', bla: 'bla2' });
}
Support for Socket.IO has been added using startup script extension
var path = require('path');
exports.startup = function (context, done) {
var io = require('socket.io')(context.app.server);
io.on('connection', function(socket){
socket.on('chat message', function(msg){
io.emit('chat message', msg);
});
});
context.app.get('/public/chat.html', function(req, res) {
res.sendfile(path.resolve(__dirname, '../public/chat.html'));
});
done();
}
For details see: http://azure.microsoft.com/blog/2014/08/26/how-to-use-socket-io-with-azure-mobile-service-node-backend/
Socket.io is not currently supported.
In may be possible to get it working, but you would need to do this code inside of your mobile services startup script, http://blogs.msdn.com/b/azuremobile/archive/2014/01/14/new-startup-scripts-preview-feature-in-azure-mobile-services.aspx, using the App object provided there.
You'd also need to update the routes on it so your routes are picked up before the mobile service ones.
#stepanic, you might try bundling the Socket.io client as a static file. Here's how we do it in Sails for reference:
From the docs:
<!-- .... -->
</body>
<script type="text/javascript" src="./path/to/bower_components/sails.io.js"></script>
<script type="text/javascript">
// `io` is available as a global.
// `io.socket` will connect automatically, but it is not ready yet (think of $(document).ready() from jQuery).
// Fortunately, this library provides an abstraction to avoid this issue.
// Requests you make before `io` is ready will be queued and replayed automatically when the socket connects.
// To disable this behavior or configure other things, you can set properties on `io`.
// You have one cycle of the event loop to change `io` settings before the auto-connection behavior starts.
io.socket.get('/hello', function serverResponded (body, sailsResponseObject) {
// body === sailsResponseObject.body
console.log('Sails responded with: ', body);
console.log('with headers: ', sailsResponseObject.headers);
console.log('and with status code: ', sailsResponseObject.statusCode);
});
</script>
</html>
Browser can't find socket.io.js for client:
<script src="/socket.io/socket.io.js"></script>
When server is created without handler:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs');
app.listen(80);
//without this part:
/*function handler (req, res) {
fs.readFile(__dirname + '/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}*/
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
I don't need and don't want handler function because everything I generate in PHP. And sometimes use client application functions for another file than index.html/php
So how to make browser can find socket.io.js?
I've wrote a demo app that you could have a look at if you don't want to loose to much time getting started with socket.io and Express 3.
To have websockets working your client js needs to be delivered from a webserver. This is one of those many browser limitation.
The easiest setup is to have a node server that provide both the client side Js and the WebSockets. Using easier the http module of Express (a bit overkill but super practical if you want to build something more than just a test app).
Other wise you need to have your client side js pointing to the right place. For example if you run your socket.io server of port 8080 and you deliver your static client side on port 8000 (using python -m SimpleHTTPServer for example or port 80 using a regular apache).
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
If you don't need access to http module functionality use this way:
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Include this on your client side !
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
var io = io.connect();
Okay, I have a simple test server set up using socket.io in node.js. My goal is to run the same server on a few different ports to test some load balanced conditions and synchronization tests.
Here is what the server looks like:
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
port = process.argv[1]; // listen on port number passed via command line
app.listen(port);
function handler (req, res) {
console.log('request', {remotePort: req.connection.remotePort, remoteAddress: req.connection.remoteAddress, url: req.url});
// how do I pass the port number here?
fs.readFile(__dirname + '/chat.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading chat.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
// do chatty stuff
});
The question is: what is the easiest way to get the port number into chat.html (see comment in code above)? Is there a way to do this with node or fs? Do I need to Express set up with templates?
Wonder what node will let me do with the query string; could I just stick the port in there and pick it out with jQuery once the page loads?
Thanks, in advance!
html is for static contents. so you can not use for dynamic contents.
so easiest way is using templates like ejs, jade and jquery template.
but you don't want you can change contents from chat.html
function(err, data) {
data = data.replace() // like this
}
I'm not recommend this way.
This is an old question, but decided to answer it with a more suiting answer still.
Because you're listening on the same port on both the http and socket.io, you can just change the script on the client to connect to the same address as the webpage was loaded, like so:
var socket = io.connect(window.location.href);
If the server was just a normal websocket server, you could do instead this:
var socket = new WebSocket(window.location.href.replace('http', 'ws'));