Web sockets

If you've ever thought about creating a high performance multiplayer game in HTML5 then the new web sockets API is just the thing you've been looking for. If you haven't done much with socket programming before, this is what you've been missing: instead of establishing a connection to a server each and every time a resource needs to be requested, a socket simply creates a connection once, then the client and server can communicate back and forth over that same connection. To put it another way, imagine making a phone call to someone, saying "Hello", then hanging up the phone after the other person says "Hello" back to you. Then, you call that person again, wait for them to pick up the phone and once you're both ready, you ask the person on the other side of the line how he or she is doing. After receiving an answer, you again hang up the phone. This continues for the duration of the conversation, where you only ask a question at a time (or make a single statement at a time), and most of the time is spent with both of you waiting for the call to come in and connecting the phones.

Now, with socket programming, the above scenario would be like making one phone call, then having the entire conversation without ever hanging up the phone. The only time you would hang up the phone would be when the conversation is finally over, and you and the other person have said good bye, and agreed to put down the phone. In this situation, there is virtually no delay between question and answer—only whatever intrinsic delay is involved in the sound traveling from one phone to another.

In HTML5, the sockets API is divided into two parts, namely a server part and a client part. The server side of the socket is something we will not discuss too much in this book, given the nature of what's involved. The client-side interface is where we will spend most of the discussion, although you will be happy to know that the JavaScript interface for web sockets and web workers is nearly identical.

// Step 1: Open connection
var con = new WebSocket
  ("ws://localhost:8888/packt/sockets/multiplayer-game-server");

// Step 2: Register callbacks
con.addEventListener("open", doOnOpen);
con.addEventListener("error", doOnError);
con.addEventListener("message", doOnMessage);
con.addEventListener("close", doOnClose);

function doOnOpen(event) {
  var msg = document.createElement("p");
  msg.textContent = "Socket connected to " + event.srcElement.URL;
  document.body.appendChild(msg);
}

function doOnError(event) {
  var msg = document.createElement("p");
  msg.textContent = "Error: " + event;
  document.body.appendChild(msg);
}

function doOnMessage(event) {
  var response = JSON.parse(event.data);

  var msg = document.createElement("p");
  msg.textContent = "Message received: " + response.message;
  document.body.appendChild(msg);
}

function doOnClose(event) {
  var msg = document.createElement("p");
  msg.textContent = "Socket connection closed at " +
    event.timeStamp;
  document.body.appendChild(msg);
}

// Step 3: Send a message to the server
con.send("Hello!");

As you can see from the preceding code snippet, there aren't too many differences between the web socket interface and the web worker interface. Most notably, perhaps, is the actual interface through which we can post a message to the server. Whereas a web worker uses the postMessage function, a web socket uses the send function. The traditional event handling functions work the exact same way as with workers. There are four events associated with a socket, namely onOpen , onClose , onError , and onMessage. The first two events, onOpen and onClose, are called when the server successfully validates the request and upgrades the connection with the browser and when the server somehow closes a connection with the particular socket, respectively. The onError event is fired when an error occurs on the server application. Finally, when the server pushes a message to the client, the JavaScript handle to the socket is alerted through the onMessage callback function. The event object that is passed to the function, similar to a web worker onMessage event object, has a data attribute with the actual data sent to it, as well as a timestamp attribute indicating when the message was sent.

The connection

Understanding the way a web application connects to a backend server through a web socket is fundamental to learning how the socket API works. The first point to remember is that the protocol that connects the browser to the server is different from the usual HTTP connection. The way a browser keeps the connection open with the server is by using the new WebSocket protocol, which is done by following a few steps. The WebSocket protocol is based on the traditional TCP and uses HTTP to upgrade the connection between a browser and a backend server, as illustrated in the following screenshot:

The connection

When we create an instance of the WebSocket class in JavaScript, the browser attempts to establish the persistent socket connection with the server. The first thing that happens is that the browser sends an HTTP request to the URI specified in the WebSocket constructor. This request contains an upgrade header, specifying that it wishes to upgrade the connection to using the WebSocket protocol. The server and the browser then perform a typical handshake, which, for the purposes of this book will not be explained in any great detail. If you're interested in implementing your own backend server application to handle this low-level handshake, you can refer to the official web socket documentation online.

To be brief, the client sends this HTTP request to the server, including a header containing a key, which is a simple text string. The server then hashes and encodes that string and sends back an HTTP response, which the browser then validates, and accepts the protocol upgrade if everything is right. If this handshake is successful, the browser proceeds to instantiate the WebSocket object, which we can then use to communicate with the server over the same connection.

The server-side code

A typical use case for web sockets is a multiplayer game where two or more players either play against each other or otherwise share the same game, in real time, but from different locations. One way such a game could be implemented (say, a fighting game such as Street Fighter or Mortal Kombat) is by having two players connecting to the server from separate computers, then the server would receive input from both players and send them the output computed from their actions. Each player's client application would then simply render the data received from the server. For example, player A presses a key on the keyboard that makes the character controlled by player A jump. That data is sent to the server, which is keeping track of where the character is and whether it can jump, and so on. After the server computes what is to be done based on the input it received from player A (in this example, the server determines that player A's character is now performing a jump), it sends the updated state of player A's character to both player A and player B. Their application then simply renders player A's character up in the air. Of course, each player's local instance of the game also renders the state it calculates from a local player's actions in order to provide instant feedback. However, the server-side instance of the game has the ability to invalidate any game state resulting from input from either player, if it is determined to be invalid. This way, both players can experience a very smooth, responsive multiplayer gaming experience, while the integrity of the game remains in check.

Now, depending on the specific language in which the server-side code is implemented, this could either be a trivial task or a real nightmare. Overall, the main thing that this server-side code needs to keep track of is all of the sockets connected to it. Obviously, the complexity of the application will be relative to the goals of the game. However, as far as the web sockets API is concerned, the main point is to pass data back to the client using the send interface function and check on input from the onMessage function.

The client-side code

As we saw in the previous code snippet, working with the JavaScript WebSocket object is very straightforward. Two things to keep in mind, however, are that every call to WebSocket.send is asynchronous and whatever data is padded to WebSocket.send must be (or will be converted to) a DOMString. That means that if we send an object, a function, or anything else to the server, it will be available to the server as a UTF-16 encoded string. If we send a JSON string to the server then all we need to do is parse the data and access the specifics. However, if we simply send an actual object, such as a literal JSON object, the server will receive something such as the following code snippet:

// Client code
var con = new WebSocket
  ("ws://localhost:8888/packt/sockets/multiplayer-game-server");
// …

con.send({name: "Rodrigo"});


// Server code
String input = get_input_from_socket();
input.toString() == "[object Object]";

Thus, when sending objects through a web socket, JavaScript will not attempt to encode the object, but will instead simply call the object's toString function and send the output of that along to the socket.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.32.67