A team had been evaluating using NodeJS for a turn based multi player game’s server. For learning, they were using the built in net api component. They manged to get a basic two player messaging system going, first with an HTML (with XMLHttpRequest) test-client, then a Flash/SWF test-client. They still seemed to be having intermittent issues with the system’s reliability and trying to create a second game room (so that 4 players are connected in all) was also problematic with occasional crashes.

To help sort out the issues, I started learning a little NodeJS by looking at the docs and experimenting with samples. At first I didn’t quite understand the createServer functionality, I kept thinking back in terms of socket programming (in C) that I had learnt many years ago. I then looked at the code base the team had for the server – I had looked at it once earlier with another developer and I asked him whether he tried adding a few traces to better explain/understand what socket was in play at various points in time. He had said that using console.log with JSON.stringify was crashing the program. The developer had somehow got it working by using a few global variables as hacks. Another issue was the socket being closed and re-connected once again when the SWF was embedded in the browser (as opposed to running it directly from the IDE).

This time I tried tracing the net and socket object in the echo server sample and the game server code base. Upon doing so, I ran into the crash:

"TypeError: Converting circular structure to JSON"

A little reading showed that (as the error itself almost always states) a circular structure is an object which contains a reference to itself in its properties (or somewhere down the chain – property’s property). If this exception weren’t caught, the existing stringify implementation would be stuck in an infinite loop (creating an infinitely long string).

I felt getting some form of trace was the quickest way to better understand what was going on in this program. After a quick search to see if there was anything equivalent to a “shallow stringify”, I hacked one up [Gist]:

At first shallowStringify traced too much – function bodies which were properties of the socket object were also traced. I tweaked the helper to skip these (just trace the function’s name). This traced enough information to help identify which object was active where at various times.

Turned out that createServer offers functionality in a simpler manner or at a higher level than what I was thinking. The issue turned out to be the global variables that the developer had used. He too perhaps had been thinking in another language when he wrote the code. This is Javascript – it’s got closures and function scope. The handlers that he wrote for the events did not know which socket they were for.

// socket object available here.
// The handler was set up similar to:
client.on('data', onData);
// ...
function onData(data) {
  // handle data

Thanks to closures, the socket could be passed in.

// socket object available here.
// The handler was changed to up similar to:
client.on('data', function(data) { 
  onData(data, socket);
// ...
function onData(data, socket) {
  // handle data

By changing the code to pass in the socket like this, he got rid of the global variables and the code also began working for multiple game rooms. Plus everyone finally understood why the previous hack worked intermittently and why the new code worked correctly. As far as the double connection when the SWF was embedded in the browser was concerned, it turned out that the first request was for the cross domain policy file.

This entry was posted in Computers and Internet, NodeJS. Bookmark the permalink.

Leave a Reply

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

You are commenting using your 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