Last friday we had a techrally at Xebia. We could pick our subject: MongoDB or Websockets or Canvas. I teamed up with Albert. There also was another websockets team consisting of Mischa, Ron and Frank.
We decided to use Jetty for websockets. No particual reason to pick Jetty, we both heard it did something with websockets and in the end it was an easier solution than the other team picked (jWebSocket).
Since we only had a few hours we were in quite a hurry, but in the end it was so simple we had time to write a blog, listen to Dan North and Albert even redid everthing and more in Python.

Introduction

I want to skip the introduction because a lot has been written about websockets and you probably want to get started as soon as possible. Check out the sources section for more information. For now you only have to know that it's fast, it has almost no overhead, keeps a permanent connection open (so the server can push data to the client, no polling required!) and best of all: it's very easy.

Installation

When you're using maven 2+ you don't have to download anything. Just start a maven war project and add the jetty-maven-plugin (we used version 7.2.1.v20101111), add a dependency to jetty-websocket (inside the project element) and you're ready to get started.
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-websocket</artifactId>
<version>7.2.1.v20101111</version>
</dependency>

Dissecting the WebSocketChatServlet example

A sample application is included with Jetty. On this blog this sample is explained and in the end we used it to see what was happening and of course see some communication between client and server. After that we stripped everything and started over again to see what was actually happening.

Creating your own servlet

Since I used Struts and Spring MVC in the past and always copied the servlet configuration it was a while ago I added my own servlet to web.xml, so here is a litte snippet to help you (this probably was one of the most difficult parts 😉 ):
<servlet>
<servlet-name>hw</servlet-name>
<servlet-class>com.xebia.ws.HelloWorldServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>hw</servlet-name>
<url-pattern>hw.do</url-pattern>
</servlet-mapping>

The HelloWorldServlet extends WebSocketServlet and you have to implement the doWebSocketConnect method. This method returns a WebSocket. For now it's enough to do a new HelloWorldWebSocket.

HelloWorldWebSocket implements WebSocket. The onConnect method receives an Outbound object. With this object it is possible to send data back to the client. The Outbound object is a field on the WebSocket object so we can use it in the onMessage method.

The onMessage method:

public void onMessage(byte opcode, String data) {
    outbound.sendMessage("pong");
}

When we send data in javascript (with send()) the server will respond with "pong".

The Javascript side

The Javascript is also very simple. I added the jQuery plugin to add data to a div with id bla, but your free to do it the old-fashioned way.

var ws=new WebSocket("ws://10.0.0.230:8080/hw.do");
ws.onmessage = onMessage;
ws.onopen = onOpen;

function onMessage(m) {
    $("#bla").append(m.data + "<br/>");
}

function onOpen() {
    console.log("connection open")
}

function send(){
console.log("sending ping");
    ws.send("ping");
}

For testing we're using Safari, it has a really nice console (available under the menu Develop, Show Error Console). By typing send() in the console we're sending a ping which will respond with a pong. The response is logged to the div with id bla.

It's even possible to write a simple websocket client with nothing more than the console:

var m=new WebSocket("ws://10.0.0.230:8080")
m.onmessage=function(m){ console.log(m.data); };

This piece of code prints the payload of any received message. Sending is done with m.send("data to send");

Problems

Thinking http is the protocol of websockets

We used the browser to test whether the WebSocketServlet was working. Of course websockets uses the ws:// or ws:// prefix and we used http://. I made this mistake a couple of times.

WebSocket is not ready

We tried to send data over the socket, but got an INVALID_STATE_ERR. It appeared the WebSocket isn't ready immediately after creating. After the WebSocket is ready the onopen function is called and then it's ready to send and receive. The readyState field on a WebSocket is a useful field to check the status of the socket (0=connecting, 1=open, 2=closing, 3=closed). So don't try to do anything with the websocket before onopen is called.

WebSocket disabled in Firefox 4

While we were coding away Dan North paid us a visit. In a very cool improvisation style presentation he pointed us to an article about some security issues with websockets.

Conclusion

Websockets is a very cool technology and I'm very happy it was a subject of the techrally. Feel free to ask any questions. At least 5 people at Xebia are now websockets experts and even more listened to two presentations about it.

Sources

http://blogs.webtide.com/gregw/entry/jetty_websocket_server
http://dev.w3.org/html5/websockets/
http://blog.dannorth.net/
http://www.slideshare.net/spagalloco/introduction-to-websockets
http://docs.codehaus.org/display/JETTY/Maven+Jetty+Plugin
http://hacks.mozilla.org/2010/12/websockets-disabled-in-firefox-4/
HTML5 Series: Part 6: WebSockets