The websocket protocol specification is approaching final and the Jetty implementation and API have been tracking the draft and is ready when the spec and browsers are available.   More over, Jetty release 7.5.0 now includes a capable websocket java client that can be used for non browser applications or load testing. It is fully asynchronous and can create thousands of connections simultaneously.

This blog uses the classic chat example to introduce a websocket server, client and load test.

The project

The websocket example has been created as a maven project with groupid com.example.  The entire project can be downloaded from here.   The pom.xml defines a dependency on org.eclipse.jetty:jetty-websocket-7.5.0.RC1 (you should update to 7.5.0 when the final release is available), which provides the websocket API and transitively the jetty implementation.  There is also a dependency on org.eclipse.jetty:jetty-servlet which provides the ability to create an embedded servlet container to run the server example.

While the project implements a Servlet, it is not in a typical webapp layout, as I wanted to provide both client and server in the same project.    Instead of a webapp, this project uses embedded jetty in a simple Main class to provide the server and the static content is served from the classpath from src/resources/com/example/docroot.

Typically developers will want to build a war file containing a webapp, but I leave it as an exercise for the reader to put the servlet and static content described here into a webapp format.

The Servlet

The Websocket connection starts with a HTTP handshake.  Thus the websocket API in jetty also initiated by the handling of a HTTP request (typically) by a Servlet.  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.

We create the ChatServlet with an init() method that instantiates and configures a WebSocketFactory instance:

The WebSocketFactory is instantiated by passing it an Acceptor instance, which in this case is an anonymous instance. The Acceptor must implement two methods: checkOrigin, which in this case accepts all; and doWebSocketConnect, which must accept a WebSocket connection by creating and returning an instance of the WebSocket interface to handle incoming messages.  In this case, an instance of the nested ChatWebSocket class is created if the protocol is “chat”.   The other WebSocketFactory fields have been initialised with hard coded buffers size and timeout, but typically these would be configurable from servlet init parameters.

The servlet handles get requests by passing them to the WebSocketFactory to be accepted or not:

All that is left for the Servlet, is the ChatWebSocket itself.   This is just a POJO that receives callbacks for events.  For this example we have implemented the WebSocket.OnTextMessage interface to restrict the call backs to only connection management and full messages:

The handling of the onOpen callback is to add the ChatWebSocket to the set of all members (and remembering the Connection object for subsequent sends).  The onClose handling simply removes the member from the set.   The onMessage handling iterates through all the members and sends the received message to them (and prints any resulting exceptions).

 

The Server

To run the servlet, there is a simple Main method that creates an embedded Jetty server with a ServletHandler for the chat servlet, as ResourceHandler for the static content needed by the browser client and a DefaultHandler to generate errors for all other requests:

The server can be run from an IDE or via maven using the following command line:

The Browser Client

The HTML for the chat room simply imports some CSS and the javascript before creating a few simple divs to contain the chat text, the join dialog and the joined dialog:

The javascript create a room object with methods to handle the various operations of a chat room.  The first operation is to join the chat room, which is triggered by entering a user name.  This creates a new WebSocket object pointing to the /chat URL path on the same server the HTML was loaded from:

The javascript websocket object is initialised with call backs for onopen, onclose and onmessage. The onopen callback is handled above by switching the join div to the joined div and sending a “has joined” message.

Sending is implemented by creating a string of username:message and sending that via the WebSocket instance:

If the chat room receives a message, the onmessage callback is called, which sanitises the message, parses out the username and appends the text to the chat div:

Finally, the onclose handling empties the chat div and switches back to the join div so that a new username may be entered:

With this simple client being served from the server, you can now point your websocket capable browsers at http://localhost:8080 and interact with the chat room. Of course this example glosses over a lot of detail and complications a real chat application would need, so I suggest you read my blog is websocket chat simpler to learn what else needs to be handled.

The Load Test Client

The jetty websocket java client is an excellent tool for both functional and load testing of a websocket based service.  It  uses the same endpoint API as the server side and for this example we create a simple implementation of the OnTextMessage interface that keeps track of the all the open connection and counts the number of messages sent and received:

The Websocket is initialized by calling open on the WebSocketClient instance passed to the constructor.  The WebSocketClient instance is shared by multiple connections and contains the thread pool and other common resources for the client.

This load test example comes with a main method that creates a WebSocketClient from command line options and then creates a number of ChatLoadClient instances:

Once the connections are opened, the main method loops around picking a random client to speak in the chat room

Once all the messages have been sent and all the replies have been received, the connections are closed:

The project is setup so that the load client can be run with the following maven command:

And the resulting output should look something like:

Yes that is 649603 messages per second!!!!!!!!!!! This is a pretty simple easy test, but it is still scheduling 1000 local sockets plus generating and parsing all the websocket frames. Real applications on real networks are unlikely to achieve close to this level, but the indications are good for the capability of high throughput and stand by for more rigorous bench marks shortly.

 

 

 

Websocket Example: Server, Client and LoadTest
Tagged on:                 

16 thoughts on “Websocket Example: Server, Client and LoadTest

  • Pingback:Greg Wilkins: Websocket Example: Server, Client and LoadTest

  • Pingback:Websocket Example: Server, Client and LoadTest | Eclipse | Syngu

  • August 24, 2011 at 6:12 pm
    Permalink

    Hi Greg,

    Thanks for the article. When is Jetty 7.5.0 and cometd 2.4.0 scheduled to be GA?

    – Suvanan

    • August 24, 2011 at 11:56 pm
      Permalink

      September 1 is the target date. RC’s are available already.

  • Pingback:Jetty WebSocket Client API updated | Webtide Blogs

  • January 21, 2012 at 1:11 pm
    Permalink

    great article thanks a lot. it works as dynamic web project in eclipse as well, without embedding jetty into the app. the only thing i found was chat object missing in client javascript room. if anyone needs, adding the following after onopen function solves the error.
    chat : function(text) {
    if (text != null && text.length > 0)
    room._send(room._username, text);
    },

  • January 30, 2012 at 10:19 am
    Permalink

    Load testing is the process of putting demand on a system or device and measuring its response. Load testing is performed to determine a system’s behavior under both normal and anticipated peak load conditions. It helps to identify the maximum operating capacity of an application as well as any bottlenecks and determine which element is causing degradation.

  • February 21, 2012 at 11:53 pm
    Permalink

    Hi, I have tried following the steps in creating the server but I cannot understand what classes I am to import. Is Jetty an API that is used in the example please? Thanks,

    • April 8, 2012 at 8:59 pm
      Permalink

      Hi JanThanks for the quick response. Good news .A clean nitsall and build of r91 worked perfectly (webapps are available and working) aftermvn nitsall (complains that no path to android home)mvn -Dandroid.home= nitsall./deploy.shBut I then attempted to repeat the process delete i-jetty, check it out again, same steps as above and was back at the same state as in my previous post. ie i-jetty apparently working but the webapps don’t appear.The only difference between non-working and working states was a reboot in between. So I rebooted and the problem was resolved. I am now unable to replicate the problem at all.Therefore it must have been something about my machine’s state (Ubuntu 8.04 inside VirtualBox on OSX 10.5.4).My apologies for taking up your time with the problem. If I _can_ replicate it I’ll let you know.Thanks again.Steve

  • February 22, 2012 at 12:35 am
    Permalink

    Do you know of any way that we could possibly move the websocket out to a different thread?

    • April 8, 2012 at 8:48 am
      Permalink

      Hi Huadong,Well, even if dynamic class idloang is supported by the jvm, there’s still a way to go to make webapplication development easy. For example, to support jsp on-the-fly compilation, the Dalvik jvm would need to support byte-code-generation, and as I understand it this is also missing.As that facility is missing, in order to support jsps, you’d need to precompile them, and precompile them for the Dalvik jvm. So you’d need to mess around with generating the java code using jspc, then run the Dalvik compiler on the generated files. So that just makes webapp dev that bit more difficult.Leaving aside jsps, and the need to compile your whole webapp with the Dalvik compiler, there’s still the issue that there’s no way of sharing libraries on the Dalvik platform. So, for example, it would be convenient if you could use the published jetty libs from the i-jetty project rather than having to import the sources into your project and build them.In the short term, if you want to do webapp development, I’d stay away from jsps, selectively import the jetty sources into your webapp project, and then write a little class with a main to start a jetty server and deploy your webapp (some examples are in the examples/embedded directory of the jetty distro).If the future, I’d like to write a jetty deployer that would be able to load an Android .apk bundle that contains a webapp from say the sdcard.regardsJan

  • April 17, 2012 at 8:58 am
    Permalink

    Hello

    i’m using jetty to make a chat application in my website.
    but i’m asking, if it’s possible to create a websocket session between 2 users?
    or in generally , to choose which user you want to talk with.
    assuming that there is just one server…

    thanks for the reply

  • June 28, 2012 at 10:47 pm
    Permalink

    I can talk directly to the jetty server just fine, but how can I put the Jetty server behind an Apache front end? Ideally I’d like to put several Jetty servers behind the Apache web server and load balance them. From my reading I think the typical mod_proxy in apache doesn’t work with web sockets.

  • March 25, 2013 at 5:20 am
    Permalink

    The term load testing is used in different ways in the professional software testing community. Load testing generally refers to the practice of modeling the expected usage of a software program by simulating multiple users accessing the program concurrently. As such, this testing is most relevant for multi-user systems; often one built using a client/server model, such as web servers. However, other types of software systems can also be load tested. For example, a word processor or graphics editor can be forced to read an extremely large document; or a financial package can be forced to generate a report based on several years’ worth of data. The most accurate load testing simulates actual use, as opposed to testing using theoretical or analytical modeling.

Comments are closed.