Join The Community

Tuesday, July 12, 2011

HTML5 Websockets for fun

During the development of our product jooink.com (the web platform that names our company and that is going to be released; if you’re interested you can ask for an invite at http://www.jooink.com) we faced the problem of letting users to interact smootly and to exchange information in real time. For the actual purposes of jooink long polling and a few tricks to let aggregation of messages in single responses is enough but we were interested and courious to experiment how the recently introduced html5’s websockets behave.
Preliminary experiments on the platform appeared to be really promising but measuring interactivity on jooink is hard because of the large codebase and because it has been optimized for long-polling, so  we started a tiny pet-project just to “measure” websockets behaviour.
The code has been presented at the GTUG session during Google Country Day that Firenze GTUG organized with Google Italia (goo.gl/sXpqb).

Being just a test we posed some rules to ourselves: weekend-app, no more than a couple of days of development (reads, ugly code), trivial graphics, an easy to understand application, interactive, GWT based.

Being unable to figure out a better application we ended developing a game, a classical game: pong

Interactivity in this game is vital and also it is quite obvious how to implement the program: we must share between the browsers the ball position and the players positions; somewhere we must have the code to let the ball bounce on borders and on players and to acknowledge the eventual winner.

Wrapping the javascript native object Websocket in GWT is quite trivial and we do not spend time here to describe the wrapper (our is almost identical to http://code.google.com/p/gwt-comet/source/browse/trunk/src/net/zschech/gwt/websockets/client/WebSocket.java ) what is important is to know that after opening the connection to the server (the uri is something like ws://hostname/...) we get an object able to send text messages, through a “send(String msg)” method, and to receive asynchronous messages through an handler (onMessage(String msg)) that is called by the browser.

Server-side we chosen to use jetty 8 (actually because jetty is the container we use in production so we feel comfortable with it). Even if we found that the online documentation is not so exhaustive, it is quite straightforward to write a serverside-websocket with jetty; the following is the echo responder websocket you can find searching google for “jetty websocket sample”, slightly modified to be jetty 8 ready.


EchoResponder:
public class EchoResponder extends WebSocketServlet {
   private static final long serialVersionUID = 1L;
   public EchoResponder() {
   super();
    }
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws       
                          ServletException, IOException {
   response.getWriter().println("EchoResponder");
   }
 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws
                                     ServletException, IOException {
   getServletContext().getNamedDispatcher("default").forward(request, response);
   }
 public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
   return new TheWebSocket();
   }
 class TheWebSocket implements WebSocket, WebSocket.OnTextMessage {
   Connection outbound;
   @Override
   public void onClose(int arg0, String arg1) {
   System.out.println("CLOSE");
   }
   @Override
   public void onOpen(Connection connection) {
   System.out.println("OPEN");    
   outbound = connection;
   }
   @Override
   public void onMessage(String msg) {
try {
   this.outbound.sendMessage(msg);
   } catch (IOException e) {
   e.printStackTrace();
   }
}
   }
}


On the other hand a snippet of the client code using the websocket in gwt looks as the following:


private TinyHandler h = new TinyHandler() {

   @Override
   public void onOpen(JavaScriptObject o) {
...
   }

   @Override
   public void onClose(JavaScriptObject o) {
   ...
   }

   @Override
   public void onMessage(JavaScriptObject o,String data) {
Window.alert(“message:” + data);
}
   public void onError(JavaScriptObject o) {
}
   };

Websocket ws = Websocket(uri, onOpenHandlers,onCloseHandler,onMessageHandler);

ws.send(“Hello world”);



The “game logic” of pong is trivial and elastic collisions are really easy to code in 2D but we chosen to be lazy so we decided to base the game on a physics engine (actually, it is more fun because we can later develop different games): Jbox2d. JBox2D  is the java porting of
Box2D an impressive C++ library  that handles very well rigid body interactions (aka collisions) and physical simulations.

So, at the end of the first day of our two days project we ended with a code working as in fugure:




The code clien-side consisting of a few hundred of lines of java devoted to receive messages and to draw in a browser’s canvas.
Server-side the code was more chunky, because of the required threads to handle the physical simulation: nothing problematic but a bit more harder to code and to maintain that we would like.
The major drawback was: writing a different game require an almost completely new server-side component (ok, desiging better the code would help in reusing the it but does not solve the problem, an almost new server component for any new game).
Fortunately looking on code.google.com we found that someone did a great job for us: JBox2D has been GWT ported. We where so amused of this idea that we switched for our last day of game development to a new approach:  a generic server controlling the logic of playgrounds (i.e. places where players can start a game: enter and create a playground, join an available playground) and just working as a hub (an old network hub) in each playground, i.e.
for any given message received from a player send it to all the adversaries, nothing more.

On the other side, on the client, we embedded gwtBox2d and let one of the players’s browser to work as a master:






the result is at http://goo.gl/OzkLw (there must be 2 players that connect simultaneously so you must wait for another visitor or … ask a friend to connect).


Unfortunately where we reached this point the weekend ended so we had no opportunity of developing other multi-user games other than pong (we will come back asap) but as a side effect of the new approach we where able to build also a single user, browser only (i.e. no need of network connection to play, at least if you leave the game in a browser tab) you can try at: http://goo.gl/IqpCU.

Of course the next step is going to be to let the code on the client to fully take advantage of html5 using webworkets that may let us to better tune timing on the browser of the ‘master’ player: maybe next weekend :P

By: Alberto Mancini (Firenze-gtug mancini@gtugs.org)
Francesca Tosi (Firenze-gtug tosi@gtugs.org)

0 comments:

Post a Comment