Download Android App


Alternate Blog View: Timeslide Sidebar Magazine

Sunday, February 12, 2012

Getting started with HTML5 WebSockets and Java - Part 1

Any technology around HTML5 seems to be a hot button topic these days and lucky for me that I got an opportunity to take a deep dive into WebSockets. Be it canvas, geolocation, video playback, drag-and-drop or WebSocket , there is a lot of buzz around these upcoming technologies.

Some background on HTML5 WebSockets

HTML5 WebSocket defines a bi-directional, full-duplex communication channel operates through a single TCP connection. The important thing to note is the WebSocket API is being standardized by the W3C, and the WebSocket protocol has been standardized by the IETF as RFC 6455.

What this means is that there are bunch of protocol versions and today's browsers support specific protocols versions only. e.g. Chrome 14, Firefox 7 and Internet Explorer 10 are currently the only browsers supporting the latest draft specification ("hybi-10") of the WebSocket protocol. The same goes for web servers. Different web servers are in varying stages of support for asynchronous messaging, with Jetty, Netty and Glassfish being the best options currently a provide native WebSocket support.

Tomcat 7 currently does not support WebSockets, yet. Check out the following issue tracker entry to learn more about the current state of affairs in Tomcat 7:

https://issues.apache.org/bugzilla/show_bug.cgi?id=51181

Socket.IO provides a default implementation for Node.JS.

It is expected that HTML5 WebSockets will replace the existing XHR approaches as well as Comet services by a new flexible and ultra high speed bidirectional TCP socket communication technology.

Technical details about WebSocket
  • Uses WebSocket protocol instead of HTTP
  • True full duplex communication channel; UTF8 strings and binary data can be sent in any direction at the same time.
  • It is not a raw TCP socket
  • Connection established by "upgrading" (handshake) from HTTP to WebSocket protocol
  • Runs via port 80/443 and is firewall/proxy friendly
  • Supports WebSocket ws:// and secure WebSocket wss://
Benefits of using WebSockets
  • Reduces network traffic. each message has 2 bytes of overhead
  • Low latency
  • No polling overhead
In tests run by Kaazing Corp, who have been closely involved in the specification process, it was found that "HTML5 Web Sockets can provide a 500:1 or - depending on the size of the HTTP headers - even a 1000:1 reduction in unnecessary HTTP header traffic and 3:1 reduction in latency";.

In short: Web Sockets can make your applications faster, more efficient, and more scalable.

The WebSocket Interface:



interface WebSocket {

....

//ready state
const unsigned short CONNECTING = 0;
const unsigned short OPEN = 0;
const unsigned short CLOSING = 0;
const unsigned short CLOSED = 0;

..
//Networking
attribute Function onopen;
attribute Function onmessage;
attribute Function onerror;
attribute Function onclose;
boolean send(in data);
void close();
};


A typical Javascript client:



var wsUri = "ws://echo.websocket.org/";

function init() 
 { 
 testWebSocket(); 
 }

function testWebSocket() 
 { 
 websocket = new WebSocket(wsUri); 
 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) 
 { 
 writeToScreen("CONNECTED"); 
 doSend("WebSocket rocks"); 
 } 

  function onClose(evt) 
 { 
 writeToScreen("DISCONNECTED"); 
 } 

  function onMessage(evt) 
 { 
 writeToScreen('RESPONSE: ' + evt.data+''); 
 websocket.close(); 
 } 

  function onError(evt) 
 { 
 writeToScreen('ERROR: ' + evt.data); 
 } 

  function doSend(message) 
 { 
 writeToScreen("SENT: " + message); 
 websocket.send(message); 
 }

function writeToScreen(message) 
 { 
 var pre = document.createElement("p"); 
 pre.innerHTML = message; 
....
 }

Getting started with WebSockets with Java backend

To build applications around websockets, I will focus on Jetty, Netty and Atmosphere for building websocket applications. The focus will be on backend processing. JQuery or raw Javascript can be used as client. We will work with a sample chat application.

1. Jetty 8

Jetty is a Java-based HTTP server and servlet container. Jetty 8 is Servlet 3.0 container and provides WebSocket implementation, so that it is possible to offer server push via both HTTP and WebSocket protocol. Jetty provides WebSocket implementation as a subclass of HttpServlet. Here is a Jetty server example:



@WebServlet(urlPatterns = "/chat", asyncSupported = true)
public class ChatServlet extends WebSocketServlet {

        // GET method is used to establish a stream connection
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
         //Implementation
        }

        // POST method is used to communicate with the server
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
  //Implementation
 }

        @Override
        public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
                return new ChatWebSocket();
        }

 private Queue webSockets = new ConcurrentLinkedQueue();
        class ChatWebSocket implements WebSocket.OnTextMessage {

                Connection connection;

                @Override
                public void onOpen(Connection connection) {
                        this.connection = connection;
                        webSockets.add(this);
                }

                @Override
                public void onClose(int closeCode, String message) {
                        webSockets.remove(this);
                }

                @Override
                public void onMessage(String queryString) {
                        // Parses query string
                        UrlEncoded parameters = new UrlEncoded(queryString);                        

                        Map data = new LinkedHashMap();
                        data.put("username", parameters.getString("username"));
                        data.put("message", parameters.getString("message"));


                        try {
                                messages.put(new Gson().toJson(data));
                        } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                        }
                }

                @Override
                public void onClose(int closeCode, String message) {
                        webSockets.remove(this);
                }
        }
}


The advantage of this approach is that it means that WebSocket connections are terminated in the same rich application space provided by HTTP servers, thus a WebSocket enabled web application can be developed in a single environment rather than by collaboration between a HTTP server and a separate WebSocket server.

2. Atmosphere

Atmosphere is a WebSocket/Comet web framework that enables real time web application in Java. Atmosphere really simplifies a real time web application development and works with servlet containers that do not implement Servlet 3.0 but natively support Comet such as Tomcat 6. Here is an exmaple:



public class ChatAtmosphereHandler implements
                AtmosphereHandler {

        public void onRequest(AtmosphereResource resource)
                        throws IOException {
                HttpServletRequest request = resource.getRequest();
                HttpServletResponse response = resource.getResponse();

                request.setCharacterEncoding("utf-8");
                response.setCharacterEncoding("utf-8");

                // GET method is used to establish a stream connection
                if ("GET".equals(request.getMethod())) {
                        // Content-Type header
                        response.setContentType("text/plain");
                        resource.suspend();

                // POST method is used to communicate with the server
                } else if ("POST".equals(request.getMethod())) {
                        Map data = new LinkedHashMap();
                        data.put("username", request.getParameter("username"));
                        data.put("message", request.getParameter("message"));


                        // Broadcasts a message
                        resource.getBroadcaster().broadcast(new Gson().toJson(data));
                }
        }

        public void onStateChange(AtmosphereResourceEvent event)
                        throws IOException {
                if (event.getMessage() == null) {
                        return;
                }

                sendMessage(event.getResource().getResponse().getWriter(), event.getMessage().toString());
        }

        private void sendMessage(PrintWriter writer, String message) throws IOException {
                // default message format is message-size ; message-data ;
                writer.print(message.length());
                writer.print(";");
                writer.print(message);
                writer.print(";");
                writer.flush();
        }
}


Conclusion

There are many resources on www describing websockets; and many libraries trying to solve the application portability problem. To a developer trying to embrace the upcoming websockets technology, it can be confusing and overwhelming.

For others who want to integrate websockets into an existing application, there is dilemma about choosing the framework and technology stack. Building applications around HTML 5 websockets is going to be tricky for next few months till the API and protocols are standardized and the open source community provides native implementations. Using Atmosphere and jWebSockets makes sense as it abstracts out the underlying provider.

I will be writing more about Atmosphere and jWebSocket in my future blog posts.

Further reading:

http://www.html5rocks.com/en/tutorials/websockets/basics/
http://websocket.org/
http://en.wikipedia.org/wiki/WebSockets

Part 2: 

No comments:

Post a Comment