Monday, April 21, 2014

HTML5 and WebSockets

As the title sais I run into some tests the newly HTML5 feature, WebSockets. What I found was pretty much nice as a general conclusion, but also brings up the very downside, the maturity of the WebSockets.

To begin the article I would like to make sure we are all on the same page: the scope for the present article is to create a simple hello world app using HTML5 WebSockets, or a first step as I like to call it.

Lets start with the basic components:
  1. the client side logic
  2. the server side logic

The client side logic:
What I understood from reading many tutorials and articles regarding WebSocket API on the internet is that we need to create a new class called WebSocket wrapped up into the browsers core engine, so you have to access it via JavaScript. Here is a list containing the browser compatibility and WebSockets, http://caniuse.com/websockets. 
The WebSockets class contains a set of events helpful for open, close and communicate via the socket.

The server side logic:
Contains the logic for creating a socket serving as a server and listening for a connection. There are specific headers that have to be sent in order to do the handshake correctly, which could be pretty tricky at first sight.

So, here is the code:

Client side: index.html 
<html>
<body>
 Html5 WebSockets test
 <script type="text/javascript">
  console.log('Entering the WebSocket logic...');
  
  if ("WebSocket" in window) 
   console.log('WebSocket is supported by your browser.');
 
        var serviceUrl = 'ws://127.0.0.1:8890/test';
        var protocol = 'test';
        var websocket = new WebSocket(serviceUrl);
  
  
  websocket.onopen = function (evt) { onOpen(evt) };
  websocket.onclose = function (evt) { onClose(evt) };
  websocket.onmessage = function (evt) { onMessage(evt) };
  websocket.onerror = function (evt) { onError(evt) };

  function onOpen(evt) {
   console.log("Connected to WebSocket server.");

   websocket.send("WebSocket message");
  }
  function onClose(evt) { console.log("Disconnected"); }
  function onMessage(evt) {
   console.log('Retrieved data from server: ' + evt.data);   
  }
  function onError(evt) { console.log('Error occured: ' + evt.data); }  
 </script> 
 </body>
</html>


Server side code: test.php

<?php
set_time_limit(60);
class WSocket {
  public $headers = array();
  public function run() {
  
  $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  socket_bind($socket, '127.0.0.1', 8890);
  socket_listen($socket);
  
  $client = socket_accept($socket);
  

  while(true) {
   if (($buf = @socket_read($client, 2048, PHP_NORMAL_READ)) === false) {
    echo "socket_read() failed: reason: " . socket_strerror(socket_last_error($socket)) . "\n\r";
    break;
   } else{
    $buf = $this->http_parse_headers($buf);
    $secKey = $buf["Sec-WebSocket-Key"];
    if($secKey != null) {
      $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
      $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
      "Upgrade: websocket\r\n" .
      "Connection: Upgrade\r\n" .
      "WebSocket-Origin: 127.0.0.1\r\n" .
      "WebSocket-Location: ws://127.0.0.1:8890/test.php\r\n".
      "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
      socket_write($client, $upgrade, strlen($upgrade));
      break;
    }
   }
  }
  @socket_shutdown($socket);
 }
 
 public function http_parse_headers ($raw_headers) {
        $headers = array();
    
        foreach (explode("\n", $raw_headers) as $i => $h) {
            $h = explode(':', $h, 2);
            
            if (isset($h[1])) {
                $headers[$h[0]] = trim($h[1]);
            }
        }
        
        return $headers;
    }
}
$ws = new WSocket();
$ws->run();

Hope you'll enjoy this small test for HTML5 WebSocket. You can visit my webpages: reduceri tricouri, pret adidasi or reduceri genti de vara 2014.