animesh kumar

Running water never grows stale. Keep flowing!

WebSocket and node.js: why shud’ya care?

with 26 comments

[tweetmeme source=”anismiles” only_single=false http://www.URL.com%5D

Traditional HTTP messages are heavy. Every message is sent with HTTP headers. Now, let’s say you have an application that has a real-time component, like chat or some twitter client or may be some traffic analysis stuff. And let’s say you have around 100,000 users connected to your app. To make your app real-time, you need to have a mechanism which will enable server to push data almost as soon as this data becomes available. You could do it in two ways: Write a script which will connect to server every few seconds to check if there is any data. With each attempt, full set of HTTP headers moves back and forth between client and server. That’s not very efficient. To save yourself with all these bandwidth hassles, you could use a popular trick known as long-polling, where your browser connects to server and server holds the connection open until there is some data available to be pushed.

Now, let’s assume that there are 100,000 users connected to your app and every 10 seconds some data is sent from server to clients. Following HTTP specs, every time some data is sent, full set of headers are shared between client and server. This is how they look,

Request header

GET / HTTP/1.1
User-Agent: ...some long user agent string...
Host: animesh.org
Accept: */*

Response header

HTTP/1.1 200 OK
Date: Tue, 25 Jan 2011 17:32:19 GMT
Server: Apache
X-Powered-By: PHP/5.2.3
X-Pingback: http://animesh.org/endpoint/
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=UTF-8

That’s approximately 350 bytes of data, per user every 10 seconds. That’s roughly 28,400,000 bits per second of network throughput for 100,000 users. Roughly 26.7 Mbps for only HTTP headers. Gosh!

WebSocket

WebSocket comes to resue. With web sockets, once a handshake is done between client and server, messages can be sent back and forth with a minimal overhead. That’s awesome. You do a handshake while establishing the connection, and of course handshaking needs all those HTTP headers, but after that, you only need to send the data… no headers. This greatly reduces the bandwidth usage and thus improves the performance. Let’s see how. This is how handshake headers look like,

Handshake Request header

GET /demo HTTP/1.1
Upgrade: WebSocket
Connection: Upgrade
Host: animesh.org
Origin: http://animesh.org
WebSocket-Protocol: sample

Handshake Response header

HTTP/1.1 101 Web Socket Protocol Handshake
Upgrade: WebSocket
Connection: Upgrade
WebSocket-Origin: http://animesh.org
WebSocket-Location: ws://animesh.org/
WebSocket-Protocol: sample

And now, the connection has been established and data can freely flow between server and client without having to exchange any HTTP headers until this connection is closed or broken and you do another handshake. Imagine how much bandwidth you are saving! Whoa!

Example

Let’s write a simple application to see and learn how this thing actually works. This application will have a server all the clients will connect to, and whenever one client writes something to the server, all clients will be notified.

Here is our server, written in Node.js. Let’s name it server.js

Note: Though you can very well write a web socket server using Node’s native APIs, however I chose to use Micheil Smith‘s node-websocket-server library. This library is simple, elegant and very easy to work with. It works by wrapping and extending Node’s server object.

var sys = require("sys");
// Library https://github.com/miksago/node-websocket-server
var	websocket = require('./lib/node-websocket-server/lib/ws/server');

// create web socket server
var server = websocket.createServer();
// listen on port 8078
server.listen(8078);

// when the server is ready
server.addListener("listening", function() {
  sys.log("Listening for connections on localhost:8078");
});

// when a traditional HTTP request comes
server.addListener("request", function(req, res) {
	res.writeHead(200, {
		"Content-Type" : "text/plain"
	});
	res.write("This is an example WebSocket server.");
	res.end();
});

// when a client websocket connects
server.addListener("connection", function(conn) {

	// when client writes something
	conn.addListener("message", function(message) {

		// iterate thorough all connected clients, and push this message
		server.manager.forEach(function(connected_client) {
			connected_client.write(JSON.stringify(conn.id + ": " + message));
        });
	});
});

Now, let’s write a simple client. We will create one HTML file and run it in Google Chrome. Let’s name is client.html

<!DOCTYPE html>
<html>
<head>
    <title>WebSocket - Simple Client</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.js"></script>
    <script type="text/javascript">

	$(function() {
		// bind form
		$('#payload-form').submit(function() {
			var payload = ($("input#payload").val());
			socket.send(payload);  // write to server
			return false;
		});

		// open websocket
		var socket = new WebSocket('ws://localhost:8078');

		socket.onopen = function() {
	    	// Web Socket is connected. send an initial random message.
	    	socket.send(Math.floor(Math.random()*11) + ' >> Hi, I am Mr. so-and-so!');
	    };
		// append to '#log' whatever server pushes.
		socket.onmessage = function(ev){
			msg = JSON.parse(ev.data);
			$('#log').append(JSON.stringify(msg) + '</br>');
		}
	})
    </script>
</head>
<body>
	<div id='payload-container'>
		<form id='payload-form'>
			<input type='text' name='payload' id='payload' value='Hello World' style="width:500px;"/>
			<input type='submit' value='push'/>
		</form>
	</div>

	<div id='log' style='display:block; border:1px solid lightgray;'></div>
</body>
</html>

Now, run your server, and open your client in multiple Chrome windows/tabs.

// run server
$ node server.js

That’s it! Was is fun? I will write more on how to establish WebSocket connections from a Java client in the next blog.

Advertisements

Written by Animesh

January 25, 2011 at 3:25 pm

26 Responses

Subscribe to comments with RSS.

  1. I really like your transitions and quality. I have been writing for Ghost Writers for a while now, and they pay me very well to write blog posts like this, or articles. I clear $100-$200 on a poor morning.
    Judging by your ability with the english language, you may enjoy doing the same.
    It wouldnt hurt to check them out.Here are the details

    Writers Wanted

    February 1, 2011 at 3:41 pm

  2. […] a server and all clients connect to this server, and send and receive messages. We decided to use WebSocket for underlying connection between clients and server, and Phonegap to build clients. Our idea is to […]

  3. Thank you for preparing such an article. Respect and affection, Marc suzkerberg

    filmler indir

    February 4, 2011 at 1:56 am

  4. you have got an awesome blog here! would you wish to make some invite posts on my weblog?

    Sherill Jumbo

    February 16, 2011 at 7:16 am

  5. […] have already explored why node.js is quickly becoming the most popular kid in school. We chose the platform for Clickdummy specifically because we are a team of JavaScript experts […]

  6. I love the simplicity and clarify of this demo. I’ve been messing with Node.js and thinking about trying WebSockets lately, and your example here (esp. turning the form submit into a socket message) has given me new ideas. =)

    Darren Torpey

    May 10, 2011 at 6:06 am

  7. Animesh, I am new to Node.JS and I am bit confused whether it is a Server like nginx, Apache etc. or a server side scripting language like PHP, Python etc or it can be used for both purposes. I have been doing a lot of work from a couple of days to get my hands dirty with node.js. In some posts you wrote a server code and I found a screen scraping code which is much like PHP curl library for the same purpose.

    Rajiv Charan Tej K

    July 9, 2011 at 8:53 pm

    • Rajiv,

      I think it would be very wrong to compare Node with Nginx, Apache like servers or PHP, Pyhton like languages. Node is much different and much more than that.

      Node is basically an eco-system built upon Google’s V8 engine using Javascript as its language. If you come form Java background, you can look at Node like a NIO implementation like Netty, Grizzly or Apache Mina. These frameworks allow you to write NIO based event-oriented network programs, like the way Node does. But, again Java suffers from decades of blocking/synchronized programming whereas Javascript it fully asynchronous.

      Few weeks ago, IBM developer works published a very basic know-how on Node. Unfortunately even they could not catch a lof of things correctly. You might want to take a look at: https://anismiles.wordpress.com/2011/05/13/ibm-has-no-idea-what-node-js-is/

      I hope, after reading these blogs, you would have a better understanding about what exactly node is. Ping me, if you need any more clarification.

      -Animesh

      Animesh

      July 9, 2011 at 9:18 pm

      • Animesh – great blog! I would like some more details on how node.js compares to Grizzly. We have a node.js backend supporting a REST api. We are considering moving to jersey/grizzly mainly for the tools, but would like to make sure that we are not compromising performance in any way. If node.js is just being used to serve up REST responses, do you think its a good move to jersey/grizzly?

        Ram

        December 3, 2012 at 4:24 am

  8. Nice introduction to web-sockets. The first para also makes a good case for SPDY, the web protocol that’s gaining acceptance.

  9. can you please help me with simple code to consuming asp.net soap web services.

    ashik

    April 25, 2012 at 11:32 pm

  10. Hello my family member! I want to say that this article is amazing, nice written and come with almost all significant infos. I’d like to peer more posts like this .

  11. Hi Animesh. I followed your client example written in this page:

    https://anismiles.wordpress.com/2011/02/03/websocket-support-in-android%E2%80%99s-phonegap-apps/#comment-706

    And your example written above in order to test my Android Websocket Client. But I got this error in logCat:

    Uncaught Error: onerror not implemented. at file:///android_asset/www/websocket.js:88

    Do you know please how to fix it?

    Maher

    November 18, 2012 at 9:55 pm

    • Probably, you should implement onError method in websocket.js file and tie that up with the backend java class. Let me know it helps, otherwise, I will try to take a look. It used to work earlier, but recently websocket drafts were revised and something must have broken for my phonegap-websocket implementation.

      Jai Ho! Animesh Kumar http://www.animesh.org

      On Sun, Nov 18, 2012 at 9:55 PM, animesh kumar

      testrahatkosh

      November 18, 2012 at 11:37 pm

  12. Hello Animesh..wonder full job you done…i have a vc++ application in server…i want to send data into that server from android-phonegap applivcation..How can i achieve it?I am beginner in websocket implementation

    jadeer

    March 4, 2013 at 11:34 pm

  13. Aw, this was a very good post. Taking a few minutes and actual effort to produce a top
    notch article… but what can I say… I procrastinate a lot and
    never seem to get nearly anything done.

    Sun Servers

    March 27, 2013 at 1:46 am

  14. I hardly leave a response, however I looked at
    a few of the comments on this page WebSocket and node.

    js: why shud’ya care? | animesh kumar. I actually do have 2 questions for you if it’s allright. Is it simply me or do some of the responses look like they are left by brain dead individuals? 😛 And, if you are writing on additional social sites, I’d like to
    keep up with everything new you have to post. Would you
    make a list of every one of your public pages like your Facebook page, twitter
    feed, or linkedin profile?

  15. Hi

    i am using your code But it not calling open function , message function .I am using cordova 2.3.
    Thanks

    dsf

    June 25, 2013 at 9:56 am

    • websocket-android-phonegap

      // new socket

      //var socket = new WebSocket(‘ws://192.168.12.171:8101/’);
      //var socket = new WebSocket(‘ws://192.168.12.171:8101’);

      document.addEventListener(“deviceready”, onDeviceReady, false);
      function onDeviceReady() {
      alert(“Ready”);
      var socket = new WebSocket(‘ws://192.168.12.171:8101/’);
      //socket.onmessage();
      }

      // push a message after the connection is established.
      socket.onopen = function() {
      alert(“open”)
      socket.send(‘Hello World’)
      };

      // alerts message pushed from server
      socket.onmessage = function(msg) {
      alert(msg);
      alert(JSON.stringify(msg));
      };

      // alert close event
      socket.onclose = function() {
      alert(‘closed————‘);
      };

      // now, close the connection after 10 seconds. (funny!)
      setInterval(function() {
      // socket.onopen();
      socket.onmessage;
      }, 100);

      dsf

      June 25, 2013 at 9:57 am

  16. […] WebSocket and node.js why shud’ya care « animesh kumar https://anismiles.wordpress.com/2011/01/25/websocket-and-node-js-why-shud%E2%80%99ya-care/ […]


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

%d bloggers like this: