Websockets from scratch - Results from a short techrally

Jeroen van Wilgenburg

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

Comments (7)

  1. Albert - Reply

    December 15, 2010 at 12:41 pm

    I used eventlet to create the python implementation:
    http://eventlet.net/doc/modules/websocket.html

    5 lines of code and you've got a websocket server running!

  2. [...] team consisting of Mischa, Ron and Frank. We decided to use Jetty for websockets. No particual... [full post] Jeroen van Wilgenburg Xebia Blog websockets 0 0 0 0 [...]

  3. Hugo - Reply

    December 16, 2010 at 11:50 am

    Websockets: a solution waiting for a problem?
    We have TCP, so now we have firewalls.
    Now we have websockets, so we will use gateways to block them?
    Point is: there is a reason why firewalls exists. This reason is still there, so websockets is a doomed technology.

  4. Rene - Reply

    January 11, 2011 at 9:35 am

    Hi Jeroen van Wilgenburg,

    this is a very interesting post about your experiences with WebSockets.

    I used the WebSocketChatServlet in Jetty to see how it is working as well, and it worked fined. But when I started to do some own tests, 2 problems occurred I am not sure of how to solve them:

    1) Is there any good explanation on the Jetty implementation, and how it should be used? (since http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/websocket/WebSocket.html is not a very detailed explanation)

    2) To me it seems that it is only possible to send strings via websockets (e.g. ws.send("ping") on client-side, outbound.sendMessage("pong") on server-side). I would like to send binary data, too (for example, to send audio data). Is there any possibility you can recommend?

    BTW, since I am new to programming, I would highly appreciate your help. Thanks in advance!!

  5. Jeroen van Wilgenburg - Reply

    January 12, 2011 at 10:16 am

    1) Try to implement all methods and print all the parameters with a System.out.println, this will give you a lot of information. Is there something particular you're stuck with?

    2) In Jetty there is a method onMessage(byte opcode, byte[] data, int offset, int length) and sendMessage(byte opcode, byte[] data, int offset, int length) which implies it can send/receive binary data, so it should be possible. I haven't tried it myself.

  6. Rene - Reply

    January 13, 2011 at 2:37 pm

    Hi Jeroen,

    thanks a lot for your fast response!!

    According to 2):
    I thought the same way, but the WebSocket protocol of I. Hickson (http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76) said

    " !!! WARNING: At this time, the WebSocket protocol cannot be used to send binary data. Using any of the frame types other than 0x00 and 0xFF is invalid. All other frame types are reserved for future use by future versions of this protocol."

    Instead the new draft edition (http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-04#section-4.3) of 11 Jan 2011 says

    "Broadly speaking, there are types for textual data, which is interpreted as UTF-8 text, binary data (whose interpretation is left up to the application), and control frames, which are not intended to carry data for the application, but instead for protocol-level signaling, such as to signal that the connection should be closed."

    but in another paragraph

    " The protocol is intended to be extensible; future versions will likely introduce a mechanism to compress data and might support sending binary data."

    Well, I think the new protocol answers to my question, so sending binary data should be possible. (although the protocol is still a draft version, i.e. not finished yet)

    A short overview what I would like to do:
    What I would like to do someday is an implementation of a Voice over IP (VoIP) via WebSockets. Until now, on the client side I used the method send(), e.g. ws.send(myAudioDataReadAsBinaryString) to send data to the server. On the server side I used the method onMessage(byte frame, String data) to receive the data as a string and simply sent it back with sendMessage(frame, data), just as the Jetty WebSocketChatServlet example does. So it´s still a long way to go 🙂

    Well, I´ll just keep trying and following the news about WebSockets... 🙂
    Cheers

  7. Ezequiel Gonya - Reply

    January 25, 2011 at 6:39 pm

    Don't consider every short comment as spam, its not - but here my two cents. It's all about fitness mates! Or what do you think? I like this info and it has presented me some sort of commitment to succeed for some reason, so thank you. Moreover I磎 definitely considering mentioning these figures in my own blog!

Add a Comment