Pages

Sunday, February 7, 2010

NodeJS + WebSockets = Stoopid Easy Comet Chat

A few weeks ago, amix wrote a blog post about Plurk's use of NodeJS for Comet chat.

He didn't post source code (as far as I could tell, after searching for two minutes :) but I was able to cobble something together yesterday along the same lines.

Here's the client:

and server:


This works with Guille's node.websocket.js library.  Start with that, then add chat.js into ./modules.

One last tweak is you have to add onDisconnect to node.websocket.js.  I did that by adding the following:


if (this.module.onConnect) {
    this.module.onConnect(this);
}


to the end of Connection.prototype._handshake. I suppose it could be called from elsewhere but that seems to work.

Check out amix's blog - lots of interesting details about how Plurk scales out to over 100,000 open connections. Hint: you don't do it with one thread per connection. The Servlet/CGI model is starting to look pretty old and creaky these days.

Update: bru has a node.websocket.js fork that includes a comet chat app. It's more complete than what I've posted here and he appears to have worked around the missing onConnect by just adding new connection objects in the onData callback.

8 comments:

  1. WebSocket's simplicity on both the client and server side is what attracted me to it a few weeks ago.
    Since then I've launched an actual site that uses WebSocket.
    Since only the latest bleeding edge chrome builds natively support WebSocket, I used the truly great flash emulated version from here: http://github.com/gimite/web-socket-js

    Since launching I've had a lot of people complain about it not working. I always followed it up with "Do you have flash?" and they always replied with No, or they had it blocked or had a really old version.

    This convinced me that flash alone is not enough emulation to cover all the users.

    So I've been working on WebSocket emulation using a comet server. At first I tried using Orbited, but it had issues running cross-domain in certain browsers.
    Now I've been using Ape-Project.org and last night I had success!

    I'm working on polishing things up so I can post the info somewhere.
    Essentially it uses native support when available, falling back to flash emulation if flash is installed, otherwise it falls back to websocket emulation/proxy with comet ape.

    Works great!

    It doesn't get in the way and allows you to code just against websocket on both the client and the server and allows you to support almost everyone.

    ReplyDelete
  2. I tried your example 1:1 on an Ubuntu installation in an VirtualBox @ Windows 7. Using the newest Chrome release I don't get an connection established.

    Since cloning a git repository only worked with the http:// protocol and not with git:// I thought maybe ubuntu doesn't know what to do with the ws:// protocol. Could that be the reason for not getting an connection to the websocket server?

    I wonder if you have any idea or tip for me how to go on? Would really appreciate that!

    Best regards from Austria

    ReplyDelete
  3. @David:Wie geht's? :) I'm not sure, but I think the protocol portion of a URL is handled by the browser, not the OS. Are you using an up-to-date chrome install? They added websocket support back in December: http://blog.chromium.org/2009/12/web-sockets-now-available-in-google.html

    I'll try it out on Ubuntu (I did this all on OSX) later and see if I can reproduce your problem. Also, NodeJS has gone through some major API changes since I wrote this so the server code could be out of date too.

    ReplyDelete
  4. Es geht gut! Bei dir auch alles okay?

    Yeah Chrome is up to date. Freshly downloaded and installed. I found someone with an OSX so I will try your example there and if it's still not working I finally have a reason to get really into nodejs :)

    ReplyDelete
  5. This looks intersting. One question I have is on large scale of users, is there any suggestions/thoughts on how to deal with sending out the notifications in a more parallel fashion? Looping through 10,000 users seems inefficient

    ReplyDelete
  6. @rooster 808: If the connection.write() method is blocking, then yes, it's a huge bottleneck. I think in this case it's async though, which means your overhead is a 10,000 item for-loop which is basically instantaneous on modern hardware. Hmm. Though you'd still have 10,000 copies of the written data (one byte array per server connection), but you could optimize that by sharing a single output byte array with multiple write counter positions (one counter per server connection). And free up the write buffer once the last writer is done.

    If you wanted to do like 10MM clients then perhaps you'd want to shard the websocket server connections over multiple machines, and have some kind of ipv6 multicast backchannel for the servers to broadcast updates to eachother (and then to their respective clients). Frankly I haven't given much thought to that particular problem but it's certainly a great question.

    ReplyDelete
  7. @robert, did you post your code somewhere? I'm interested in it, thanks!

    ReplyDelete
  8. @newyuppie:

    No, I didn't. The code with ape-project worked and I even launched a website with it, but the site didn't get very much traffic and after a few months I shut it down.

    I wouldn't use ape-project or my code again.

    This is because I feel the right approach is to use: http://socket.io/

    This basically does the same thing my code did. Uses WebSocket natively if available, falling back to flash if available, finally falling back to comet techniques.

    ReplyDelete