Caucho Technology
  • resin 4.0
  • hello, world websocket in resin


    A "hello, world" WebSocket servlet in Resin

    Demo

    WebSocket Overview

    WebSocket is a new browser capability being developed for HTML 5 browsers, enabling fully interactive applications. With WebSockets, both the browser and the server can send asynchronous messages over a single TCP socket, without resorting to long polling or comet.

    Essentially, a WebSocket is a standard bidirectional TCP socket between the client and the server. The socket starts out as a HTTP connection and then "Upgrades" to a TCP socket after a HTTP handshake. After the handshake, either side can send data.

    WebSocket handshake
    GET /test HTTP/1.1
    Upgrade: WebSocket
    Connection: Upgrade
    Origin: http://localhost/test
    Host: localhost
    Content-Length: 0
    
    ...
    
    HTTP/1.1 101 Web Socket Protocol Handshake
    Upgrade: WebSocket
    Connection: Upgrade
    Server: Resin/4.0.2
    WebSocket-Location: ws://localhost/websocket
    WebSocket-Origin: http://localhost/test
    Content-Length: 0
    Date: Fri, 08 May 2009 09:51:31 GMT
    
    ...
    

    WebSocket packets

    After the WebSocket connection is established, all data is encoded in lightweight packets. While the spec defines a text packet and a binary packet format, browsers use the text packet exclusively. (Resin's HMTP uses the binary packet format.)

    A text packet is the byte 0x00 followed by UTF-8 encoded data followed by a 0xff byte.

    WebSocket text packet
    x00 utf-8-data xff
    
    Example: hello text packet
    \x00hello, world\xff
    

    Tutorial Description

    Since the tutorial is a hello, world, the JavaScript just does the following:

    1. Connects to the Resin WebSocket servlet
    2. Sends a "hello" query to the servlet
    3. Sends a "server" query to the servlet
    4. Displays any received messages from the servlet

    Files in this tutorial

    FILEDESCRIPTION
    websocket.phpwebsocket HTML page and JavaScript
    WEB-INF/classes/example/WebSocketServlet.javawebsocket servlet
    WEB-INF/classes/example/WebSocketHandler.javawebsocket handler
    WEB-INF/resin-web.xmlresin-web.xml configuration

    WebSocket JavaScript

    The JavaScript for this example has been tested with the nightly build of Chromium.

    Connecting to the WebSocket in JavaScript

    Example: WebSocket connect in JavaScript
    <?php
      $url = "ws://localhost:8080/example/websocket";
    ?>
    
    <script language='javascript'>
    
    function onopen(event) { ... }
    function onmessage(event) { ... }
    function onclose(event) { ... }
    
    ws = new WebSocket("<?= $url ?>");
    wsopen.ws = ws;
    ws.onopen = wsopen;
    ws.onmessage = wsmessage;
    ws.onclose = wsclose;
    
    </script>
    

    Receiving WebSocket data in JavaScript

    Example: receive WebSocket message
    <script language='javascript'>
    
    function wsmessage(event)
    {
      data = event.data;
    
      alert("Received: [" + data + "]");
    }
    
    </script>
    

    Sending WebSocket data in JavaScript

    Example: send WebSocket message
    <script language='javascript'>
    
    function wsopen(event)
    {
      ws = this.ws;
    
      ws.send("my-message");
    }
    
    ws = new WebSocket(...);
    wsopen.ws = ws;
    ws.onopen = wsopen;
    
    </script>
    

    WebSocket Servlet

    Resin's WebSocket support is designed to be similar to the Servlet 3.0 Async API, although the requirements for WebSockets are significantly different.

    To upgrade a HTTP socket to WebSocket, the ServletRequest is cast to a WebSocketServletRequest (implemented by Resin), and then call startWebSocket(...)

    Example: Upgrading to WebSocket
    import com.caucho.servlet.WebSocketServletRequest;
    import com.caucho.servlet.WebSocketListener;
    
    ...
    public class MyServlet extends GenericServlet {
    
      public void service(ServletRequest req, ServletResponse res)
        throws IOException, ServletException
      {
        WebSocketServletRequest wsReq = (WebSocketServletRequest) req;
    
        WebSocketListener handler = new MyHandler();
    
        wsReq.startWebSocket(handler);
      }
    }
    

    The WebSocketListener is the heart of the server-side implementation of websockets. It is a single-threaded listener for client events.

    When a new packet is available, Resin will call the onRead method, expecting the listener to read data from the client. While the onRead is processing, Resin will not call onRead again until the first one has completed processing.

    In this example, the handler reads a WebSocket text packet and sends a response.

    The InputStream and OutputStream from the WebSocketContext are not thread safe, so it's important for the server to synchronize writes so packets don't get jumbled up.

    Example: MyHandler.java
    package example;
    
    import com.caucho.servlet.WebSocketContext;
    import com.caucho.servlet.WebSocketListener;
    
    public class MyHandler implements WebSocketListener
    {
      ...
    
      public void onRead(WebSocketContext context)
        throws IOException
      {
        StringBuilder sb = new StringBuilder();
    
        InputStream is = context.getInputStream();
        OutputStream os = context.getOutputStream();
    
        int ch = _is.read();
    
        assert(ch == 0x00); // packet starts with 0x00
    
        while ((ch = _is.read()) >= 0 && ch != 0xff) {
          sb.append((char) ch);
        }
    
        String message = sb.toString();
    
        String result = "received message";
    
        _os.write(0x00);
        _os.write(result.getBytes("utf-8"));
        _os.write(0xff);
        _os.flush();
      }
    }
    

    Resin's WebSocketListener has four callback methods. onRead will be called the majority of the time, and onStart called at the beginning of the connection and onComplete called at the end.

    WebSocketListener.java
    package com.caucho.servlet;
    
    public interface WebSocketListener
    {
      public void onStart(WebSocketContext context) throws IOException;
    
      public void onRead(WebSocketContext context) throws IOException;
    
      public void onComplete(WebSocketContext context) throws IOException;
    
      public void onTimeout(WebSocketContext context) throws IOException;
    }
    

    The WebSocket context gives access to the WebSocket streams, as well as allowing setting of the socket timeout, and closing the connection.

    WebSocketContext.java
    package com.caucho.servlet;
    
    public interface WebSocketContext
    {
      public InputStream getInputStream() throws IOException;
    
      public OutputStream getOutputStream() throws IOException;
    
      public void setTimeout(long timeout);
    
      public long getTimeout();
    
      public void complete();
    }
    

    Demo


    Copyright © 1998-2011 Caucho Technology, Inc. All rights reserved.
    Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.