I'm Morgan McGuire (@CasualEffects). I've been working on computer graphics and games for 20 years at great places including NVIDIA, University of Waterloo, Williams College, Brown University, Roblox, Unity, and Activision.

See my home page for a full index of my blog posts, books, research, and projects.

Tuesday, August 7, 2012

Separating the Socket.IO application and web server

This post describes how to write a simple JavaScript program with real-time client server interaction that works with a regular web server instead of creating a custom one in Node.js. This is the framework that you probably want for extending your website with network-based interactive elements or writing a browser based multiplayer game. My previous posts explained how to install Node.js and Socket.IO and how to write your first Socket.IO program. This series is essentially a transcript of what I learned while setting up multiplayer game examples for codeheart.js.

Running a Web Server on OS X Mountain Lion

The point of this post is to extend your existing web server, which assumes that you have a web server. If your site is hosted somewhere else, you can just upload the files described below to it. If you are testing or are running directly on OS X Mountain Lion, you can do the following to launch the web server. Note that OS X Lion and earlier had a GUI for launching the web server directly in the Sharing pane of Preferences, but that was removed in Mountain Lion.

At a command prompt, type:

   sudo apachectl start

That launches your webserver.  Place the files described in the following sections in the

   /Library/WebServer/Documents

directory. The file is writeable only by root in the default install, so I ran:


   sudo chown $username /Library/WebServer/Documents
   chmod u+rwx /Library/WebServer/Documents


to be able to easily modify its contents from my developer account.  To stop your web server, remember to execute:


   sudo apachectl stop

when you're done testing. The web server will automatically stop if you reboot your machine as well.



Creating the Server-side Application

I'm going to call the server-side application app.js.  It will run under Node.js.  It can run on a different machine from the web server, although for simplicity in testing I'm going to describe running them both on the same machine.  The point is that the application is on a different port from the web server and only handles network traffic directly related to the application. It does not serve files to web browsers.

The server program is just:

app.js

// Listen on port 1080 (arbitrarily chosen here and in index.html
var io = require('socket.io').listen(1080)

io.sockets.on('connection', function (socket) {

  socket.emit('myMessageType', 'Hello world');

  // Example of how the client can filter for messages.  This one
  // will not go to the messages log.  Instead it will change the
  // color of a square.
  socket.emit('colorMessage', {color: '#0F0'});

  socket.on('myResponseType', function (data) {
    console.log(data);
  });
});
You run it by typing:
sudo node app.js
at the command line.  Note that you must have previously installed Socket.IO in the same directory (see previous post on how to install Node.js and Socket.IO).



Creating the Client-side Application


The client side application is stored on the web server. It is then downloaded to the client by a web browser and executed locally. On your server, you need to store the following index.html file and the complete contents of the node_modules/socket.io/node_modules/socket.io-client/dist/ directory, which were created by the install of the server-side Socket.IO library. Put the contents of that directory into a socket.io directory, so that you have a directory structure on your web server like this:



(if you're running your web server on OS X Mountain Lion, then this is the contents of your /Library/WebServer/Documents directory).

The index.html file for this demo is:


<html>
  <head>
    <!-- Load Socket.IO from our web server, which is separate from the
  application's server. -->
    <script src="http://localhost/socket.io/socket.io.js"></script>
    <script>
      // Tell Socket.IO where to find the Flash component if the browser needs it.
      WEB_SOCKET_SWF_LOCATION = 'http://localhost/socket.io/WebSocketMain.swf';
    </script>
  </head>
  <body>
    <h1>Socket.IO Demo</h1>

    <!-- A log for messages -->
    <div id="messages" style="border: 1px solid #000; width: 100%; color: #0F0; background: #000; font-family: monospace;">
      Connecting to server...<br/>
    </div>

    <div id="colorsquare" style="border: 1px solid #000; width: 32px; height: 32px; background: #F00; margin-top: 10px;"></div>

    <script>
      // Make the output visible
      var messages = document.getElementById('messages');

      // Connect to our app.js, which is listeninging on port 1080 
      var socket = io.connect('http://localhost:1080');
      
      socket.on('connect',
        function() {
          messages.innerHTML += 'Connected<br/>';
        });

      socket.on('myMessageType',
         function(data) {
           messages.innerHTML += 'Server says: "' + data.toString() + '"<br/>';

           // Respond to the server
           socket.emit('myResponseType', { my: 'data' });
        });

      socket.on('colorMessage',
         function(data) { 
            document.getElementById('colorsquare').style.background = data.color;
         });
    </script>

  </body>
</html>

In this case, I'm assuming that both the web server and node are running on the local machine. If you have a different web server, replace "localhost/" with your server's name (but do not replace "localhost:1080/"... that's Node.js's server!)

Now load the page in your browser, for example, by pointing your browser at http://localhost/index.html


You should see the following:



The green box had its color changed from red by a message from the server. The text in quotes in the black box was transmitted by the server.

The code above shows how to connect, modify an HTML page based on network messages, and how to filter different kinds of messages. That's everything that you need in order to build arbitrary networked browser-based applications in JavaScript.





Morgan McGuire is a professor of Computer Science at Williams College and a professional game developer. He is the author of The Graphics Codex, an essential reference for computer graphics that runs on iPhone, iPad, and iPod Touch.