Cacomania: A simple Node.js based chat server

Cacomania

A simple Node.js based chat server

Guido Krömer - 18. October 2012 - Tags: ,

Since everyone talks about Node.js I wanted to try it, too. The aspect of writing server side JavaScript is interesting, using just one language for client and server side development. But this should not be the main reason taking Node.js. Since Node.js is asynchronous and event driven it can handle hundred of connections using just one single thread.

The way of processing a request is really different in comparison to a classic apache web server, having a thread pool of n threads, for example.
Classic multithreaded server
When all those threads are in use, maybe because they are waiting for the database or the file system, no new connections can be accepted even if those requests doesn’t need data from a database or file system access.

The Node.js way is a little bit different, all I/O based stuff gets binded to a callback. If the I/O got collected the callback gets executed with the loaded data. This is the same way doing ajax on the client side.

Creating a little chat server is a great warm up, even no blocking I/O or database access has to be handled. Callbacks have to be used, too. We have three callbacks, one for a new connection (net.createServer(…)), one for receiving data (socket.on(‘data’, …) and a last one which will be executed on closing the connection by the client (socket.on(‘end’, …)).

The chat server logic, including changing the nickname, sending private messages, listing all users or kicking an user, is separated into the class Clients. After a new client has connected the net.createServer callback is going to add the new client and creates the necessary callback for data and end.
The data callback tries first to handle the received data as a command, if the message from the client does not begin with a slash it must be a normal message and is going to send it to all clients.

To start the server just call nodejs with the name of the script, server.js is the name if you cloned the script via git.

[caco@A8-3870 NodeJs Test]# node server.js

Testing the server by connecting a client can be done using netcat on port 1337.

[caco@A8-3870 NodeJs Test]# netcat localhost 1337
Hello, use /help to display available commands.
New user logged in.
/users
Users online: User_1, User_2
/name Caco
User_1 changed his name to Caco
/users
Users online: Caco, User_2
/private User_2 Nice nickname!        
User_2 sends you a private message: thx
Hi @ all
/help
Available commands are:/name <YouNewName>, /kick <UserName>, /private <UserName> <your private message>, /quit, /users, /help

Now its time to start a little stress test, I connected 1000 more clients to the server which is near the maximum of my linux settings and since I’m really lazy i didn’t change the max open socket limit. The bash script below start 1000 more clients, connected to the server. With the classic universal unix fork hammer method.

#!/bin/bash
for i in {1..1000}; do
  netcat localhost 1337 &
done

Here is a part of he output generated by the /users command:

/users  
Users online: Caco, User_2, User_3, User_4, User_5, User_6, User_7, User_8, User_9, User_10, User_11, User_12, User_13, User_14, User_15, User_16, User_17, User_18, User_19, User_20, User_21, User_22, User_23, User_24, User_25, User_26, User_27, User_28, User_29, User_30, User_31, User_32, User_33, User_34, User_35, User_36, User_37, User_38, User_39, User_40, User_41, User_42, User_43, User_44, User_45, User_46, User_47, User_48, User_49, User_50, User_51, User_52, User_53, User_54, User_55, User_56, User_57, User_58, User_59, User_60, User_61, User_62, User_63, User_64, User_65, User_66, User_67, User_68, User_69, User_70, User_71, User_72, User_73, User_74, User_75, User_76, User_77, User_78, User_79, User_80, User_81, User_82, User_83, User_84, User_85, User_86, User_87, User_88, User_89, User_90, User_91, User_92, User_93, User_94, User_95, User_96, User_97, User_98, User_99, User_100, User_101, User_102, User_103, User_104, User_105, User_106, User_107, User_108, User_109, User_110, User_111, User_112, User_113, User_114, User_115, User_116, User_117, User_118, User_119, User_120, User_121, User_122, User_123, User_124, User_125, User_126, User_127, User_128, User_129, User_130, User_131, User_132, User_133, User_134, User_135, User_136, User_137, User_138, User_139, User_140, User_141, User_142, User_143, User_144, User_145, User_146, User_147, User_148, User_149, User_150, User_151, User_152, User_153,...

That’s it folks, maybe I’m going to write a second part about http or websockets with nodejs.