Going Online with WebSockets - Local Storage and Multiplayer Games - HTML5 Games: Creating Fun with HTML5, CSS3, and WebGL (2012)

HTML5 Games: Creating Fun with HTML5, CSS3, and WebGL (2012)

part 4

Local Storage and Multiplayer Games

Chapter 13

Going Online with WebSockets

in this chapter

• Using WebSockets for online communication

• Introduction to Node.js and server-side JavaScript

• Creating a simple chat application

In this chapter, I introduce you to WebSockets and Node, two relatively new technologies that make creating network applications and server-side scripting a much better experience than it has been in the past.

In the first half of the chapter, I take you through the WebSocket API and show you how to establish and manage a connection to a server as well as how to communicate with the server by sending and receiving data.

I then show you how to use Node to create server-side JavaScript applications. By the end of the chapter, you will see how to create a chat server and client using Node and WebSockets.

Using WebSockets

Traditionally, whenever network communication outside regular Ajax requests was needed, the solution was either plug-in based or a workaround using existing XmlHttpRequest technology, possibly involving long-lived connections that wait for responses from the server. HTTP wasn’t really designed with polling in mind, and HTTP requests and responses carry a lot of overhead. When all the HTTP headers, cookies, and other request data are combined, an HTTP request can easily have 1 kilobyte of overhead data. That’s a lot if you only want to send a short status update.

WebSockets were created to provide an alternative geared specifically toward persistent connections and low-latency communication. WebSockets keep the connection alive and use only 2 bytes of overhead for each message, a drastic reduction. Another really cool thing about WebSockets is that they allow for bidirectional communication. Both the client and server can send messages to each other at the same time via the same connection. The HTTP protocol limits you to sending a request and getting a response.

The protocol used to communicate via WebSocket connections is being standardized by the Internet Engineering Task Force (IETF). At the time of writing, the most recent sub protocol is version 12, which you can access at http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-12.

WebSockets are currently supported in the beta versions of Firefox and Chrome as well as on iOS devices. Development on WebSockets moves very fast, however, and it’s best to stay alert and watch for changes to the specifications and browser support. Microsoft is currently experimenting with WebSockets on their HTML5 Labs site (http://html5labs.interoperabilitybridges.com/) where you can also find a prototype version of Internet Explorer that has preliminary WebSockets support.

Connecting to servers

In the browser, WebSockets are available via a standardized API. The WebSocket API is maintained and developed by the W3C. You can access the most recent version at http://dev.w3.org/html5/websockets/. There is no API for server applications. Server developers are free to implement WebSockets any way they choose, as long as they follow the IETF protocol.

Establishing the connection

Setting up a WebSocket connection is very simple. Just create a new WebSocket object and pass the URL of the server as the first argument:

var ws = new WebSocket(“ws://www.myserver.com:9999/”);

This creates a new WebSocket object and attempts to establish a connection to www.myserver.com on port 9999. The WebSocket constructor takes an optional second argument that specifies a list of sub protocols.

Up until at least version 6 of Mozilla Firefox, the WebSocket constructor is disabled in favor of the prefixed MozWebSocket. You can do a simple test at the beginning of your application to determine which one is available and, if necessary, make WebSocket point to MozWebSocket:

window.WebSocket = window.WebSocket || window.MozWebSocket;

WebSockets can operate in both a secure and non-secure manner. The ws:// prefix in the URL indicates a non-secure connection. Use the wss:// to establish secure connections. This is similar to the http:// and https:// protocols used for HTTP connections. Note that secure connections require that the server supports them.

If you have worked with Ajax and the XmlHttpRequest object, you are probably familiar with the concept of the ready state. The ready state, which can be read from the ws.readyState property, is a numeric value that indicates the current state of the connection. Table 13-1 lists the four ready states defined by the WebSocket API.

Table 13-1 WebSocket ready states

Status code

Numeric

Description

CONNECTING

0

The client is establishing the connection.

OPEN

1

The connection is open, and you can use the send() method and the message event to communicate with the server.

CLOSING

2

The connection is in the process of being closed.

CLOSED

3

The connection is closed, and you can no longer communicate with the server.

When you first create a new WebSocket object, its ready state is set to CONNECTING. When the connection to the server is established, the ready state switches to OPEN, and you can start communicating with the server. You can use the following snippet to check whether the connection is open or closed:

if (ws.readyState === 1) {

// connection is open

}

Alternatively, you can use the status code properties available on the WebSocket object:

if (ws.readyState === ws.OPEN) {

// connection is open

}

Closing the connection

When you want to close the connection, simply call the ws.close() method:

ws.close();

Calling the ws.close() method switches the ready state to CLOSING until the connection is completely shut down, after which the ready state is CLOSED. Call the ws.close() method only after the connection is opened; otherwise, you get an error.

When the connection is closed by calling the ws.close() method or by some other event — for example, if the server closes the connection or the connections fails — the WebSocket object emits a close event:

ws.addEventListener(“close”, function() {

console.log(“Connection closed”);

}, false);

A connection may suddenly close for many different reasons, so it can be useful to know if the connection closed because it was supposed to or if some error forced it to close. For that purpose, the WebSocket protocol defines a number of status codes used to indicate the reason the connection was closed. Table 13-2 shows the currently defined status codes.

Table 13-2 Status codes for close events

Status code

Description

1000

The connection was closed normally, that is, not due to a problem.

1001

The endpoint is moving away. For the server, this could be a server shutdown; for the client, it could be due to the user navigating to a new page.

1002

The connection was closed due to a protocol error.

1003

The endpoint received unsupported data — for example, binary data when it accepts only text.

1004

The connection was closed because the endpoint received a data frame that was too large.

1005

This status code is reserved for use when no status code was received but one was expected.

1006

This status code is reserved for use where the connection was closed without sending the close frame.

1007

The connection was closed because the endpoint received invalid UTF-8 text data.

You can use these codes and the e.wasClean property to determine if the connection closed cleanly and why the connection was closed. If necessary, you can take appropriate action:

ws.addEventListener(“close”, function(e) {

if (!e.wasClean) {

console.log(e.code + “ “ + e.reason);

}

}, false);

note.eps

Firefox 6 supports only the e.wasClean property. The e.code and e.reason properties are not exposed.

You also can define and use your own status codes. The 4000 - 4999 range is reserved for private use, so if you want to implement a custom status code for your application, feel free to use a code in that range. The ws.close() method takes two optional parameters: the status code and a reason. Note that the reason string can be no longer than 123 characters.

ws.close(4100, “Player disconnected”);

Of course, you are responsible for intercepting the close event on the server and checking for these codes yourself. Because no standard API is defined for WebSocket servers, exactly how this works on the server depends on the frameworks and libraries you use.

Communicating with WebSockets

Because WebSockets are full-duplex, bidirectional connections, you need to create only one connection to be able send and receive data. This is contrasted by, for example, long-polling with HTTP connections, where you need one connection that waits for messages from the server while another connection is used to send messages to the server.

Sending messages

When the connection is open, you can send data to the server with the ws.send() method. This function takes a single argument that can be a UTF-8 string, an ArrayBuffer, or a binary Blob object:

ws.send(“Hello Server!”); // send a string to the server

If strings are not enough and you want to send more complex data types, you can, of course, always encode your JavaScript objects as JSON and decode it on the server side. The following function takes whatever you pass in the data parameter and sends it as JSON:

function sendData(ws, data) {

var jsonData = JSON.stringify(data);

ws.send(jsonData)

}

The following snippet sends an update data structure for a hypothetical game. The update data contains the current direction of movement and information about whether the player character is firing a weapon:

sendData(ws, {

move : {x : 0.79, y : -0.79},

firing : true,

weapon : 7

});

Only string data is supported at the moment, but in the future, you will be able to also send binary data using either ArrayBuffer objects or Blob objects. Chrome already has some support for these data types, but Firefox allows only strings for now.

Whenever you send a message with the ws.send() method, the data is placed in a buffer. The WebSocket object feeds data from this buffer to the network connection as fast as it can, but there’s a chance the buffer is non-empty when you send the next piece of data. If you try to send data and the buffer is completely full, not only is the data not sent, but the connection also is closed. The ws.bufferedAmount property tells you how much data is currently stored in the buffer. One possible use of this value is to limit the rate at which messages are sent. If, for example, your game sends an update to the server at a certain interval, checking that the buffer is empty before sending the data can help you avoid flooding the connection with more data than it can handle:

setInterval(function() {

if (ws.bufferedAmount == 0) {

var data = getUpdate();

ws.send(data);

}

}, 100);

Even though the interval is set to 100 ms, the preceding example sends the update data only if the buffer is empty, thereby avoiding potential congestion.

Receiving messages

When the server sends a message, a message event is fired on the WebSocket object. The event object passed to any handlers has a data property that contains the message from the server. Simply attach an event handler to the message event and process the data any way you want:

ws.addEventListener(“message”, function(e) {

console.log(“Received data: “ + e.data);

}, false);

Using Node on the Server

WebSockets are not very useful without a server to which they can connect. Many server libraries and frameworks are available already for a variety of platforms and programming languages. Node (http://nodejs.org/), or Node.js as it is also called, is a JavaScript-based framework for the server and is perfect for this purpose, not least because it lets you code in the same language on both the client and server.

Node emphasizes asynchronous patterns, which should be familiar to any JavaScript programmer who is used to developing for the browser. In the browser, Ajax and DOM events, for example, all function asynchronously. The process of attaching event handlers and passing callback functions is second nature to many, if not most, web developers. In the server-side setting of Node, this means that whenever you request access to some I/O resource (such as a file on the disk, a database, or a network connection), you pass a callback function to the given function. The function immediately returns and calls the callback function when the task is done. Listing 13.1 illustrates how you can use Node to read data from a file.

Listing 13.1 Reading Data from a File with Node

var fs = require(“fs”);

fs.readFile(“./myfiles/mystuff.txt”, function(err, data) {

if (err) {

// something bad happened

} else {

// process file data

}

});

Most of the asynchronous built-in functions follow this pattern of adding a callback function at the end of the parameter list. Similarly, callback functions almost always have an error value as the first parameter followed by any other parameters that make sense in that particular context.

The require() function imports a module. In Listing 13.1, the file system module is made available through the variable fs. Node comes with many built-in modules; you can see a complete list and read more about the functionality they provide in the API documentation:http://nodejs.org/docs/latest/api/index.html.

Installing Node

You need a server to be able to use Node, preferably one to which you have enough access that you can install new programs. The exact way to install Node depends on the server platform. Even though you can find pre-built Windows binaries on the Node web site, I recommend you use a Linux-based system because the Windows version is still unstable and doesn’t get much attention.

The following command downloads and extracts the latest Node source code:

curl http://nodejs.org/dist/node-latest.tar.gz | tar xzv

You should now have a new folder containing the Node source.

cd node-vX.X.X

The following three commands configure, build, and install Node:

./configure

make

sudo make install

If this method doesn’t fit your situation, you can find instructions for various scenarios in the Node wiki: https://github.com/joyent/node/wiki/Installation.

After you install Node on your server, you can try it out immediately by entering node at a command prompt. This command gives you a Node console where you can type in any line of JavaScript you want to execute.

Using third-party modules

As mentioned previously, Node has a lot of built-in functionality, and you can get pretty far with what’s available out of the box. However, the built-in functions are all relatively low level, and there is, for example, no built-in database functionality. Instead, Node includes all the building blocks needed to make add-on modules that provide features such as database integration, web servers, and so on. You can find an extensive list of such modules in the Node wiki: https://github.com/joyent/node/wiki/modules.

The Node Package Manager (npm) is a useful tool that makes managing your modules a breeze. You can read more about npm at the project web site: http://npmjs.org/. Installing npm can be as easy as the following one-liner, which downloads the npm installer and immediately executes it:

curl http://npmjs.org/install.sh | sudo sh

When npm is installed, you can use the npm install command to install modules. For example, to install the WebSocket module that we use later, use the following command:

npm install websocket

Similarly, you can use the npm remove command to remove any module you want to uninstall:

npm remove websocket

The npm list command gives you a full list of all installed modules. You can browse all the modules available through npm at http://search.npmjs.org/.

If you use Mac OSX, you can download packages for Node and npm at https://sites.google.com/site/nodejsmacosx/. Using these packages might be easier than taking the manual route.

Node hosting

Don’t despair if you don’t have the required access to your server and don’t have a Linux machine to experiment with. A few options are available if you just want to play around with Node.

Joyent, the company that manages Node, is currently in the process of launching a service called Node SmartMachines (https://no.de/). These SmartMachines are basically virtual servers that let you run Node applications. The service is currently in beta testing. Signing up is free, but some waiting is to be expected. I also discuss this service further in Chapter 14. Nodester (http://nodester.com/) is another free Node hosting service that is similar to Node SmartMachines.

If you would rather experiment with a Linux server, you can use Amazon’s Elastic Compute Cloud (EC2) service. With EC2, you can launch a virtual server called an instance whenever you need it and shut it down when you’re done so you don’t waste server resources. Amazon provides a free tier that lets you use an EC2 microinstance free for a year. Read more about this at http://aws.amazon.com/free/.

Follow the instructions on the Amazon Web Services site to set up an EC2 instance. You get to choose from a variety of different Amazon Machine Images (AMI), some created by Amazon and others created by the community. Ubuntu provides images for Amazon EC2 athttp://cloud.ubuntu.com/ami/. Clicking the AMI ID links takes you straight to the AWS console and initiates the AMI launch process.

If you choose an Ubuntu image, you can install Node and the websocket module with three simple commands:

sudo apt-get install nodejs

curl http://npmjs.org/install.sh | sudo sh

npm install websocket

Now we can get started with the first example. For something simple yet potentially useful, we create a basic HTTP server that always responds with the same message.

Creating an HTTP server with Node

Node provides a networking module called net. This module provides low-level socket functionality that lets you create network clients as well as server applications. Node also includes an HTTP module implemented on top of the net module. You can use this module to create servers that implement the HTTP protocol. However, the server functionality provided by this module goes only as far as managing the connection. How to interpret the requests is up to you.

Import the HTTP module with the require() method and use its createServer() method to create a new HTTP server object;

var server = require(“http”).createServer();

Use the server.listen() method to start accepting connections. This method takes three parameters: a port number, an optional host name, and an optional callback function. If the host name is left out, the server listens on all available IP addresses:

server.listen(9999); // listen on port 9999 on all interfaces

The server object fires a connection event whenever a client connects to the server. Node lets you attach event handlers by using the on() method on the target object. For example, to attach a handler to the connection event on the server object, use the following:

server.on(“connection”, function(socket) {

socket.on(“data”, function(data) {

console.log(data.toString());

});

});

The event handler receives a socket object that you can use to send and receive data. The socket object emits data events every time a piece of data is received. In this example, the data is simply written to the console.

When the server receives a valid HTTP request, it fires a request event, passing a request object and a response object to the event handlers. The request object enables you to access information about the HTTP request, such as the request path, HTTP headers, and so on. The responseobject is used to write the HTTP response to the client socket. The response object has three important methods: response.writeHead(), response.write(), and response.end().

The response.writeHead() method writes the HTTP header to the socket. The function takes two parameters: an HTTP status code (such as 200 for a successful request or 404 for “file not found” errors) and a JavaScript object containing the response headers.

response.writeHead(200, {

“Content-Type” : “text/plain”

});

The response.write() method writes the actual response data:

response.write(“It Works!”);

Finally, the response.end() method closes the connection. Listing 13.2 shows the full code for the HTTP server. You can find this example in the file 01-httpserver.js.

Listing 13.2 A Basic HTTP Server

var server = require(“http”).createServer(),

util = require(“util”);

server.on(”connection”, function(socket) {

socket.on(”data”, function(data) {

console.log(data.toString());

});

});

server.on(”request”, function(request, response) {

response.writeHead(200, {

”Content-Type” : ”text/plain”

});

response.write(”It Works!”);

response.end();

});

// output a message to the console

util.puts(“Server running on port 9999!”);

server.listen(9999); // listen on port 9999

Run the server by executing the command:

node 01-httpserver.js

When you connect to the server from a browser, you should see the text “It Works!” displayed, no matter what file or path you request.

Creating a WebSocket chat room

In the second example, I show you how to use Node and WebSockets to create a simple chat application. If you haven’t done so already, make sure the websocket module is installed by executing the following command at a command prompt:

npm install websocket

You can now import the websocket module into your Node applications:

var WebSocketServer = require(“websocket”).server,

WebSocketClient = require(“websocket”).client,

WebSocketFrame = require(“websocket”).frame,

WebSocketRouter = require(“websocket”).router;

You use only the WebSocketServer constructor in this example, but the others can be useful in other scenarios — for example, if you need to use the Node as a client to connect to a third-party server.

note.eps

Because the WebSocket API and protocol are sometimes changing rapidly, there may be some gaps between the protocol versions supported by the Node module and the versions supported by the browsers. Check the web site for the Node websocket module (https://github.com/Worlize/WebSocket-Node) for details on the current level of support.

Creating the server

First, use the WebSocketServer constructor to create a new WebSocket server object. You also need an HTTP server.

var ws = new WebSocketServer(),

server = require(“http”).createServer();

Next, you need to make a link between the WebSocket server and HTTP server. The WebSocket server essentially attaches to the HTTP server and processes any requests it receives. To create a link between the servers, you mount a server configuration object:

ws.mount(serverConfig);

The serverConfig is a simple JavaScript object that specifies a number of options and parameters for the WebSocket server, the most important being the reference to the HTTP server:

var serverConfig = {

httpServer : server,

autoAcceptConnections : true

};

Setting autoAcceptConnections to true means that the server will accept all connections, regardless of what sub protocol versions they use. In a real production setting, you should consider a stricter approach to avoid problems. For this example, being forgiving is acceptable.

If you need to stop accepting new WebSocket connections, you can unmount the server by using the ws.unmount() method. This function breaks the link to the server configuration so no new connections can be established. Any existing connections are left untouched. You can use thews.closeAllConnections() method if you also want to close existing connections. Finally, the ws.shutDown() performs both these tasks in one call.

As an alternative to using the ws.mount() method, you can pass the server configuration object directly to the WebSocketServer constructor. Listing 13.3 shows the code needed to set up the chat server so it accepts connections on port 9999. If you have a firewall running, make sure that you use an open port. You can find the complete code for this example in the file 02-websocketserver.js.

Listing 13.3 Setting Up the Server

var WebSocketServer = require(“websocket”).server,

util = require(“util”);

// create a HTTP server

var server = require(“http”).createServer(),

// and a WebSocket server

var ws = new WebSocketServer({

httpServer : server,

autoAcceptConnections : true

});

util.puts(“Chat server listening on port 9999!”);

server.listen(9999);

When a new client connects to the server, a connect event is fired on the WebSocketServer object. This event carries a connection object that you must use to communicate with that client. Listing 13.4 shows the connection handler for this event.

Listing 13.4 Handling New Connections

// create the initially empty client list

var clients = [];

ws.on(“connect”, connectHandler);

function connectHandler(conn) {

// set the initial nickname to the client IP

conn.nickname = conn.remoteAddress;

conn.on(“message”, messageHandler);

conn.on(“close”, closeHandler);

// add connection the client list

clients.push(conn);

// send message to all clients

broadcast(conn.nickname + “ entered the chat”);

}

The connectHandler() function starts by assigning a nickname to the client. This is the name that you use when sending messages to the other clients. Initially, this is set to the client’s IP address, which is available in the conn.remoteAddress property. I get back to the handlers for the message and close events shortly. The connectHandler() function finishes by adding the connection object to the clients array and broadcasting a message to all clients that a new person has entered the chat room. Listing 13.5 shows the broadcast() function.

Listing 13.5 Broadcasting the Messages to All Clients

function broadcast(data) {

clients.forEach(function(client) {

client.sendUTF(data);

});

}

This function simply iterates over all the connected clients and sends the message. Note that the method used to send the data is called client.sendUTF(); if you are sending binary data, you must use the client.sendBinary() method, which accepts a Node Buffer object.

All clients are added to the clients array when they connect, so they must also be removed when the connection closes. Listing 13.6 shows the event handler for the close event attached in Listing 13.4.

Listing 13.6 Removing Disconnected Clients

function closeHandler() {

var index = clients.indexOf(this);

if (index > -1) {

clients.splice(index, 1);

}

broadcast(this.nickname + “ left the chat”);

}

After removing the client connection from the clients array, closeHandler() sends a message to the remaining clients that the person has left the chat room.

When a client sends data to the WebSocket server, it fires a message event on the client connection object. Listing 13.7 shows the messageHandler() function attached as the handler for this event.

Listing 13.7 Handling Client Messages

function messageHandler(message) {

var data = message.utf8Data;

broadcast(this.nickname + “ says: “ + data);

}

The event handler receives a single argument, an object containing the message. String messages keep the data in the message.utf8Data property, whereas messages with binary content keep the data as a Node Buffer object available in the message.binaryData property.

The messageHandler() function in Listing 13.7 simply broadcasts the message to all clients, prefixed with the nickname of the sender. Let’s make things a bit more interesting and introduce a couple of commands that clients can issue. In particular, let’s add the following two commands:

/nick newnickname

/shutdown

The /nick command changes the client’s nickname to newnickname. The /shutdown command simply shuts down the chat server. If this were a real application, you should probably restrict access to such a command. The modified messageHandler() function is shown in Listing 13.8.

Listing 13.8 Intercepting Commands

function messageHandler(message) {

var data = message.utf8Data.toString(),

firstWord = data.toLowerCase().split(” ”)[0];

// is this a command?

if (data[0] == ”/”) {

// if so, which command is it?

switch (firstWord) {

case ”/nick” :

// new nickname is the second word

var newname = data.split(” ”)[1];

if (newname != ””) {

broadcast(this.nickname

+ ” changed name to ” + newname);

this.nickname = newname; // set new nick

}

break;

case ”/shutdown” :

broadcast(”Server shutting down. Bye!”);

ws.shutDown(); // shut down the WebSocket server

server.close(); // and the HTTP server

break;

default :

this.sendUTF(”Unknown command: ” + firstWord);

}

} else {

broadcast(this.nickname + ” says: ” + data);

}

}

You can find the complete Node server script in the file 02-websocketserver.js.

Creating the WebSocket client

Time to create the chat client, starting with the HTML shown in Listing 13.9. The HTML is available in the file 03-websocketclient.html.

Listing 13.9 Chat Client Markup

<!DOCTYPE HTML>

<html lang=”en-US”>

<head>

<meta charset=”UTF-8”>

<title>Chapter 13: WebSocket Chat</title>

<link rel=”stylesheet” href=”05-websocketclient.css”>

<script src=”05-websocketclient.js”></script>

</head>

<body>

<h1>Very Simple Chat</h1>

<input id=”input” placeholder=”Enter message...”/>

<textarea id=”response” disabled></textarea>

</body>

</html>

The HTML is just a basic input field that the user enters messages into and a textarea element used to display the output. Listing 13.10 shows the content of the CSS file 03-websocketclient.css.

Listing 13.10 Styling the Chat Client

#input, #response {

border : 1px solid black;

padding : 2px;

display : block;

width : 600px;

}

#response {

height : 300px;

}

The JavaScript file 03-websocketclient.js contains all the code needed to set up the chat client. When the page finishes loading, the setupChat() function shown in Listing 13.11 creates the WebSocket connection and attaches the relevant event handlers. Remember to change the URL passed to the WebSocket() constructor, if necessary.

Listing 13.11 Setting Up the Client Code

function setupChat() {

var ws = new WebSocket(“ws://127.0.0.1:9999/”);

setupInput(ws);

write(“Welcome to Very Simple Chat!”);

ws.addEventListener(“open”, function () {

write(“Opened connection”);

}, false);

ws.addEventListener(“message”, function(e) {

write(e.data);

}, false);

ws.addEventListener(“close”, function() {

write(“Connection closed”);

}, false);

}

window.addEventListener(“load”, setupChat, false);

The setupInput() function attaches a function to the keydown event on the input field. Whenever the user presses Enter, which has the key code 13, the text in the field is sent to the server and the field is cleared. Listing 13.12 shows the function.

Listing 13.12 Setting Up the Input Field

function setupInput(ws) {

var input = document.getElementById(“input”);

input.addEventListener(“keydown”, function(e) {

if (e.keyCode == 13) {

ws.send(this.value);

this.value = “”;

}

});

}

Listing 13.13 shows the last function, write(), which simply writes a line of text to the output textarea, prefixing the string with a time stamp.

Listing 13.13 Writing Output Messages

function write(str) {

var response = document.getElementById(“response”),

time = (new Date()).toLocaleTimeString();

response.value += time + “ - “ + str + “\r\n”;

}

Now you can try opening the client in a browser while the server is running. Start the server with the command:

node 02-websocketserver.js

If all goes well, you should see the welcome message followed by a message informing you that the connection is established. In the input field, you can type in messages that are then sent to the server. If you open a second browser (perhaps on a different computer) with the chat client, you see that the messages are, in fact, sent to all connected clients and the basic chat system works.

Summary

In this chapter, you learned about the server-side JavaScript environment Node and WebSocket API that enables you to create better network-enabled web applications than traditional HTTP-based solutions.

This chapter showed you how to use WebSockets to create connections to a server and how to send and receive data. You also learned how WebSockets provides a better experience than the methods used in the past when persistent connections were needed.

In introducing Node, this chapter showed you how to create a simple HTTP server in just a few lines of code. Finally, you learned, through creating a basic chat application, how Node and WebSockets can work together to create powerful web applications with efficient, low-latency network communication.