Real time notifications (part II). Now with node.js and socket.io


In one of my previous posts I wrote about Real time notifications with PHP. I wanted to create a simple comet system fully written in PHP and JavaScript. It worked but as Scott Mattocks told me in a comment this implementation was still just doing short polling. The performance with this solution may be bad in a medium/hight traffic site. This days I’m playing with node.js and I want to create a simple test. I want to do exactly the same than the previous post but now with node.js instead of my PHP+js test. Let’s start

Now I want to use socket.io instead of pure web-sockets like my previous posts about node.js. For those who don’t know, socket.io is amazing library that allows us to use real-time technologies within every browsers (yes even with IE6). It uses one technology or another depending on the browser we are using, with the same interface for the developer. That’s means if we’re using Google Chrome we will use websockets, but if our browser does’t support them, socket.io will choose another supported transports. Definitely socket.io is the jQuery of the websockets. The supporter transports are:

  • WebSocket
  • Adobe Flash Socket
  • AJAX long polling
  • AJAX multipart streaming
  • Forever Iframe
  • JSONP Polling

First we create our node.js server. A really simple one.

var http = require('http');
var io = require('socket.io');

server = http.createServer(function(req, res){
});
server.listen(8080);

// socket.io 
var socket = io.listen(server);

socket.on('connection', function(client){
  client.on('message', function(msg){
      socket.broadcast(msg);
  })
}); 

This server will broadcast the message received from the browser to all connected clients.

Our HTML page will look like that:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Comet Test</title>
    </head>
    <body>
        <p><a id='customAlert' href="#" onclick='socket.send("customAlert")'>publish customAlert</a></p>
        <p><a id='customAlert2' href="#" onclick='socket.send("customAlert2")'>publish customAlert2</a></p>
        <script src="http://localhost:8080/socket.io/socket.io.js" type="text/javascript"></script>
        <script type="text/javascript">

// Start the socket
var socket = new io.Socket(null, {port: 8080});
socket.connect();

socket.on('message', function(msg){
    console.log(msg);
});
        </script>
    </body>
</html>

As we can see we are including the js script called socket.io/socket.io.js. This script is served by our node server.

In fact we can use our node.js to serve everything (HTML, js, CSS) but in our example we will use only node.js for real-time stuff. Apache will serve the rest of the code (only a HTML file in this case).

And that’s all. Those few lines perform the same thing than our PHP and js code in the other post’s example. Our node.js implementation is definitely smarter than the PHP one. The socket.io library also allows us to use the example with all browser. Same code and without any browser nightmare (just like jQuery when we work with DOM).

Here I have a little screencast with the working example. As we will see there We will connect to the node server with firefox and chrome. Firefox will use xhr multipart and Chrome will use Websokets.

Another important issue of socket.io library is that we forget about the reconnection to the web-socket server, if something wrong happens (as we can see in Real time monitoring PHP applications with web-sockets and node.js). If we use raw WebSocket implementations and our connection with the web-socket server crashes or if we stop the server, our application will raise disconnect event and we need to create something to reconnect to the server. socket.io does it for us. With our small piece of JavaScript code we will get a high performance real-time applicatrion. Node is cool. Really cool. Kinda wierd at the beginning but the learning effort will be worthwhile. A few js lines and a real time applications.

I’ve got a problem within our node.js application. If we’ve got some kind of security within our application (imagine for example it’s behind a session based auth form) we need to share this security layer with our node.js server to ensure that non authenticated users aren’t allowed to use our websockets. I don’t know how to do it just now, but I’m investigating. Do you have any idea?

Full code Code at github. Ensure you’re using the stable version of node.js. With the last versión available on github of node.js there’s a bug and server dies when we connect with Google Chrome.

About these ads

About Gonzalo Ayuso

Web Architect specialized in Open Source technologies. PHP, Python, JQuery, Dojo, PostgreSQL, CouchDB and node.js but always learning.

Posted on May 23, 2011, in HTML5, node.js, socket.io, Technology, Websockets. Bookmark the permalink. 33 Comments.

  1. Client side: (0.7)

    // Start the socket
    var socket = io.connect(null, {port: 8080});

    socket.on(‘message’, function(msg)
    {
    console.log(msg);
    });

  2. Very neat, my fourth time going through this and i get a bit of it, but the notifications work per click/ as you click on a link, am i right? kay before i climb this tree any further, is ti possible to implement email notificatiions with this and a change of events in the database? say i insert a comment….

    • As I understand with your comment you want to send emails instead of sockets to the node server. It’s a different problem. I don’t recommend to do it innline (simple mail function). It will slow down your script. Maybe it’s better to use a queue system, for example gearman.

  3. I have to example setup but its not working as expected, how do you user xhr-multipart and websokets in the 2 browsers

  4. You can’t choose the transport. Sockect.io decides the transport depending on the browser. For example if your browser allows websokets (the best way) it will use it, if not the best transport available in your browser will be used. That’s the great thing of this library. It’s something like the jquery of the websockets.

    In my example I open two different browser to show the same code with different transports

  5. Strangely this works in Chrome, but nothing displays on console if using Firefox. And Firefox reports errors : io is not defined, socket is undefined.

  6. In order to keep the server as light as possible, I’m looking to send data to the client via node.js and then have the client do an sql lookup before updating the client view, but I’m unable to find any examples of that. Is there any reason this *wouldn’t* work? Should I be researching some different avenue?

    Basically, the server would get notified of a change through some other means (from another user or interface, for example), and would notify the client that it needed to update. Preferably, I would be specific about what needed to update instead of just doing an update for the whole page.

    • Yeah! I have exactly this idea in my mind for months. The problem is a simple web page (select to database, populate grid) turns into a more complex system (and that’s not KISS :) ). Anyway I want to play a little bit with this

  7. Hey Gonzalo,

    Im so very happy I came across your blog!
    Very high level and I could learn a lot. I’m also a php developer who recently started getting into the world of node.js. This notifications project is exactly what I want to implement BUT my stack is a bit different and my sessions solution ( as I see it in mind ) is also different from your php + node.js sessions post. But I kinda got lost in the architecture and implementation of it all, maybe you could improve this project and have a 3rd post with more robust and full solution? That would be great!
    so think about Facebook’s notifications feature at the top navigation bar. When a event occur you automatically get notified and also there are aggregated notifications. More over, the user can see ” all of his notifications “.
    My main system is php based so i thought of adding node.js for real time features and redis for sessions management between the two, and some queue (zeroMQ? RabbitMQ? else ?) for handling the notifications (per each user) eventually ( how will you aggregate the notifications in real time or near real time ).
    About the sessions between node.js and php redis can deliver Consistency and Persistency (www.cs.brown.edu/courses/cs227/archives/2011/slides/mar07-redis.pdf) which can ensure using the right session while the user is connected. Availability is minor in exchange for both.
    Will you store all processed ( aggregated or not ) on Db? ( I guess so) what db ?

    Would love to hear back
    Thanks !!!

    Shoshy

    • I must admit that I been thinking about how to solve the problem (share sessions between node and PHP) for a long time and I don’t know what is the correct solution. I wrote the post because I thought the problem was in were sessions are located, but now I don’t think the location of the session is the problem. Maybe we need to build a oauth system between php and node.js to trust the connections, but I’m not sure how to implement yet. I will think about it.

  8. Hi Gonzalo,

    I took a look at your tutorial and it’s super helpful. Right now I am trying to build a website that is mainly in php (served by apache), with a live-chat system served by socket.io. It works perfectly if you go to wundertutor.com:8000 (being served by express – I just followed a simple tutorial to make a node chat server). What I am trying to do is integrate it into my main site (wundertutor.com) but I am coming across some issues with CORS. Specifically, I am getting this error:

    XMLHttpRequest cannot load http://wundertutor.com:8000/socket.io/1/?t=1356423985952. Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.

    This puzzles me for two reasons:
    1.) When I specify the port directly and go to the page served by express, my node app successfully creates a websocket connection but when I go to the main site I encounter the error because it is trying to use XHR polling.
    2.) I have tried to set Access-Control-Allow-Origin options is both apache and my node app, as well as on the client side code – none of the options seem to work and I am going crazy trying to figure out the problem. Any thoughts?

    – Austin

    • Hi CORS is an nightmare, but if if you are the sysadmin of the webserver and you should solve it without problems with the Access-Control-Allow-Origin directive. Your error code says without doubt that your problem is with CORS. That’s means that you are in the right way but you are doing something wrong. (http://enable-cors.org/). Check your headers (with firebug or chrome developer tools) and ensure Access-Control-Allow-Origin is property enabled. Now if I go to your url i don’t see the Access-Control-Allow-Origin in the headers.

      A good resource to understand the problem is: http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/

      Moreover, Is your site behind a session based auth?. I’m not sure what’s the correct way to work with a site like yours (apache+php to serve the web and node.js for real-time) but behind a sessions (we need to “share” or something similar, sessions between node and php).

      • Thanks so much for the response! I am starting to realize cors is a nightmare for myself. As for the Access-Control-Allow-Origin directive, I have tried to set it up (even trying the link you gave me) but it doesn’t seem to do anything. Should this be done through apache? – and if so, what could I be doing wrong that is stopping it from working? Here is my .htaccess file for reference:

        #RewriteEngine On
        #RewriteCond %{HTTPS} off
        #RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
        Header add Access-Control-Allow-Origin “*”

        I have also tried this, but I still see the same error:

        Header set Access-Control-Allow-Origin “*”

        Also, I am running this website on my own vps so I have complete access to everything I want. As for the session based auth – I would like this feature to run without anyone logging in, so I am not trying to set it up with any kind of session based authentification (except what socket.io is using to keep track of separate users). Lastly, I was hoping the cors solution would solve the issue of php and node working together. I am not aware of any other way that I can have them play nicely so I am stuck right now :/

  9. I guess it didnt show the full code without the comments. Here is what I meant to put after “I have also tried this, but I still see the same error:”

    #
    # Header set Access-Control-Allow-Origin “*”
    #

  10. IfModule mod_headers.c
    Header set Access-Control-Allow-Origin “*”
    /IfModule

    Still not showing up – here is the code without the carrots before and after the ifModule statements

    • As I understand your app is a apache/php + chat with socket.io. I don’t really understand where express fits here (maybe to serve static files of chat application). Where is exactly the problem? When you try to use express resources from apache with js? or, When socket.io tries to use XHR in socket.io (because websockets are not available and uses a failback). If your situation is the first one Access-Control-Allow-Origin must be set in the node.js server. If the situation is the second one then you need Access-Control-Allow-Origin within apache.

      I know is a nightmare, but check with the inspector if your headers are properly set up. Try also to put Access-Control-Allow-Origin in all servers (in your case: apache, socket.io and express) without restrictions (‘*’), and when it works adjust the restrictions.

      You can also use chrome without this kind of security (–disable-web-security) http://stackoverflow.com/questions/3102819/chrome-disable-same-origin-policy

  11. nice entry.

    i have a problem with IE browser : “script5 access denied” when i try to using socket.io object .Could you help me with this problem ?

  12. I have a problem when follow you tutorial. The client never connects to the server. I’m using chrome Version 24.0.1312.57 m, socket.io 0.9.13 but it can’t establish a connection using websocket, always have a request 101 switching protocol in pending forever. When I set transport to ‘xhr-polling’, it works fine. Can you tell me the reason? I have looked for the answer for two days but useless.

    • It looks like you cannot speak websockets between client and server. When you use one fallback (xhr-polling) it works. Your browser’s version looks good. Check in chrome’s developer tools if something happens with ws (network tab). You can also check if you are behind a proxy or firewall. Maybe one firewall is cutting the ws and socket.io change to the fallback

      • Thanks for reply.
        When I log socket client events on chrome developer tool it like this:
        -connecting //stop at 101 switching protocol
        -connect_failed // appears when it comes to heartbeat interval, server emits heartbeat for client then after heartbeat timeout it connect and disconnect immediately like this:
        -connect
        -Test // Message from server, I just echo it on client
        -disconnect
        -connect_failed
        and never continue with this error Uncaught TypeError: Cannot call method ‘onClose’ of null on socket.io.js:1771

        You can look on server screen: http://i638.photobucket.com/albums/uu106/quangvu37/Screen.jpg
        It stop there and client never connect to server.

        I test it on localhost, I use only Avira Antivirus, and has no firewall or proxy. I have looked for other socket.io example online but still has the same result. I don’t know the reason.

        Another problem: I try using ws(https://github.com/einaros/ws) library to implement websocket on nodejs, ok, it connect, but not send data until I close the tab.
        I’m really stuck with websocket.

      • Are are using one external library to connect to socket.io from browser? You don’t need it. In fact if you want to use socket.io you need to use the js provided by socket.io in the browser (/socket.io/socket.io.js) this static file is served by socket.io.

  13. @Gonzalo Ayuso: with socket.io, I’m using your source for all server and client, I just change to ws library for server, raw websocket of browser for client when I can’t find what happen with socket.io.
    With my log and server debug screen, do you have any suggestion for me?

    • I have some tests today on other computers, it works like a charm. So I think it’s about my computer. Thanks for your suggestion Gonzalo :). Now my work is finding what’s stopping come to websocket? Firewall or Proxy :D

      Anw, great tutorial :D

  14. Something more change:
    index.html –> from two lines to one:
    var socket = io.connect(‘http://localhost:8000′);

    server.js –> no broadcast method:
    socket.sockets.send(msg);

  15. Hi Gonazalo
    I want to clear one my doubt.Currently I am working on one php-codeigniter project and there I need to display feeds/comments for authenticated users.So here is my architecture
    front-end communicates with php/codeigniter application server to get more messages on autoload using ajax i.e when user scroll down the page then more messages are fetched from server .Finally to access newly added messages in real-time is done with node.js server
    So I just want to clarify is it a good way to display feeds or any changes can be done to make it more better?

    • Auth user and websockets it’s a problem. It isn’t a problem is your all your app is built over node.js, but when you need to handle with two servers (node and PHP application) you need to share the authentication. IMHO the best way to solve the problem is described here: http://socketo.me/docs/push.

  16. This is a good interaction. I’m interested in Shared Session between node.js, PHP and Redis. I need Authenticated facebook like notification on my site. Thankyou

  17. Hi Ganzalo,

    Really great post, Is it possible to build the Android Client and IOS client for Socket.io server ? or so Socket.io only meant for web based chat ?

    How scalable it will be as there will be around 1 million active users in a day.How it differs from XMPP protocol.

    Thanks,
    Srinivas

    • socket.io (and websockets) are web technologies. I suppouse that you can use a native android/IOS client, but provably you can find better things such as push notificiations there. Anyway you can use socket.io within a phonegap application without any problem. The only problem is that you need to open the application to connect to the websocket/socket.io server (if you want to send messages with the application closed you need to use push notifications)

  18. Hi Ganzalo,

    Thank you for your comments. Do you recommend Socket.io + Redis + Node.js is good alternative to Ejabbered with XMPP for high performance Chat application ? .

    thanks,
    Srinivas

    • I work with a websockets in a private intranet (heavy use but not a big number of users and it works like a charm) I cannot speak about 1million active users in a day. Anyway as far I know whatsup an google talk uses a custom XMPP implementations. 1millon users per day is a hard job with node and ejabberd. The good thing of websockets is that new broswsers has native support and with XMPP you neet to use external libraries, but XMPP is a robust technology used for years

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 963 other followers

%d bloggers like this: