Introduction into HTML5 WebSocket
This post is for anyone who is after a quick introduction into a compelling feature of the HTML5 specification, the WebSocket. Long story short, WebSocket draws a line between conventional web design conforming to or working around the statelessness of the HTTP protocol and modern real-time data-intensive applications. WebSocket finally enables to establish a single bidirectional communication channel. Today, I would like to demo a simple application showing basic principles of this fascinating technology.
WebSocket is typically explained in the context of a simple chat application. I am no exception to this rule and here is my share on yet another chatty powered by Jetty. I believe the screenshot is self explanatory.
Apropos Jetty. I have chosen it for the general ease-of-use and minimalistic configuration. I also appreciate it is quick in adopting recent trends (see one of my previous posts SPDY via Jetty). Nevertheless, the list of WebSocket servers runs long these days. Starting with Apache MQ, Autobahn, Cramp, jWebsocket, Netty etc., up till Socket IO, vert.x and Yaws. My list is far from being exhaustive, but undoubtedly there is broad range of solutions to choose from, across all platforms, both open-source and commercial.
Back to the example, let’s take a look what the traffic looks like when people start chatting:
As you can see, there really is a single communication channel between the server and its clients. What you can see in the screenshot above is the result of the initial handshake between the browser and the server. Once established, success is acknowledged by upgrading to the WebSocket protocol, you can start sending data back and forth through the channel. If you are interested in details, the handshake mechanism is nicely explained here. Obviously, this assumes that your browser does support the technology. Paste the following javascript into your browser’s address bar as a quick check:
javascript:alert('WebSocket: ' + (window.WebSocket ? 'yes' : 'no'));
One last bit worth mentioning is the WebSocket API. Our chat makes use of three out of four specified events: onopen, onclose, onmessage.
.. import org.eclipse.jetty.websocket.WebSocket.OnTextMessage; import org.eclipse.jetty.websocket.WebSocket.Connection; import java.util.Set; .. private Connection connection; private Set<ChatWebSocket> users; public class ChatWebSocket implements OnTextMessage { .. public void onClose(int closeCode, String message) { users.remove(this); } public void onOpen(Connection connection) { this.connection = connection; users.add(this); } public void onMessage(String data) { for (ChatWebSocket user : users) { try { user.connection.sendMessage(data); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } .. }
There is not much to talk about. We merely register new subscriptions to the channel and broadcast incoming messages to all connected users. We certainly could make our solution highly sophisticated by interpreting incoming data and reacting upon their significance. But let’s keep it simple for a start.
Now, when we have the customized event listeners in place we we need a servlet capable of upgrading to WebSocket:
.. import org.eclipse.jetty.websocket.WebSocket; import org.eclipse.jetty.websocket.WebSocketServlet; import java.util.concurrent.CopyOnWriteArraySet; .. public class WebSocketChatServlet extends WebSocketServlet { private Set<ChatWebSocket> users = new CopyOnWriteArraySet<ChatWebSocket>(); public WebSocket doWebSocketConnect( HttpServletRequest request, String arg) { return new ChatWebSocket(users); } }
Finally, we configure the servlet in web.xml, no surprises here:
<servlet> <servlet-name>WebSocketChat</servlet-name> <servlet-class> org.zezutom.wschat.WebSocketChatServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>WebSocketChat</servlet-name> <url-pattern>/talk/*</url-pattern> </servlet-mapping>
That’s it for the server-side. Our client code centers around the HTML5 WebSocket object.
// JQuery + custom javascript, unimportant here.. // HTML5 WebSocket: initialization and custom handlers // as a front-end counterpart to our server-side code var _ws = new WebSocket('ws://localhost:8080/wschat/talk'); _ws.onopen = function(event) { // show that a new user joined the chatroom // and request a connection }; _ws.onclose = function(event) { // notify that the user has left // and release the connection }; _ws.onmessage = function(event) { // extract event data and display them as a new message // do all the fancy stuff (colors, highlighting, // smooth scrolling etc.) };
To conclude, I found it unusually easy to get the application’s bare bones up and running and had great fun when testing my very own chat.
On the down side, the new technology has raised several concerns. One of the most discussed area is, as usual, security. WebSocket does not use HTTP headers which impacts firewalls and virus scanners relying on them. Many exciting articles and discussions can be searched out, above all:
That’s all for today. As usual, feel free to download the source code and explore it at your own pace.
Download Source Code or Explore ItResources: