EDITING BOARD
RO
EN
×
▼ BROWSE ISSUES ▼
Issue 28

Websockets – http on steroids

Philip Peterhansl
IT Consultant Automotive
@.msg systems Romania



PROGRAMMING

Http has been around since 1999, but the modern web applications‘ increasing demand for server push and a more efficient communication protocol, led to the definition of the Websocket protocol in 2011.

The questions asked at the Java Conference 2014 in Cluj were symptomatic for the new technologies:

This article advertises Websockets and gives an overview of how to use them and the reasons, why you should use them.

Websocket security is a major topic, but cannot be covered in this article. See Useful Links for further information.

How to use websockets?

Websocket implementations share a common interface definition between server, client and even across programming languages. The following code examples will implement a basic chat example by connecting both, a Java and a Javascript client to a Java server.

Use the following maven dependency in your Java server and client projects to include the JSR-356 API for Java Websockets:

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
</dependency>

Java Server: Annotated ServerEndpoint

First, we create the server, by using the annotated ServerEndpoint defined in JSR-356. There’s also a specification for programmatic endpoint creation, but that won’t be covered in this article.

Code first, explanations below:

@ServerEndpoint(value = "/service")
public class ChatServerEndpoint {

    private static final Set connections =
            new CopyOnWriteArraySet<>();

    private Session session;

    @OnOpen
    public void start(Session session) {
        this.session = session;
        connections.add(this);
    }

}

The value property oft he ServerEndpoint defines, on which path this endpoint listens. The URL for connecting to this endpoint is ws://://.

The @OnOpen annotation marks the start method to be called, when a client connects. You should do all the initialization, that‘s necessary. In the chat example, the connecting client’s session gets stored into the connections set for later use inside the broadcast method.

What happens, if a client disconnects? Define a method, annotate it with the @OnClose annotation and it gets called everytime a client disconnects, regardless of the cause:

@OnClose
public void end() {
    connections.remove(this);
}

In this simple chat example, the disconnected client is removed from the connections set.

The core of any data driven application implementing Websockets is sending and receiving data. The most basic solution for receiving messages in an JSR Endpoint is annotating a method with the @OnMessage annotation and the following signature:

@OnMessage
public void incoming(String message) {
    broadcast(message);
}

There are more sophisticated ways of receiving (and sending) messages using encoders and decoders with text and binary messages, but they won’t be covered in this article. Have a look at the JSR-356 API for further information.

Sending messages is done via the session of the receiving client. The broadcast method steps through each connected client in the connections set and sends the message by using a BasicRemote:

private static void broadcast(String msg) {
    for (ChatAnnotation client : connections) {
        try {
            synchronized (client) {
                client.session.getBasicRemote().sendText(msg);
            }
        } catch (IOException e) {
            connections.remove(client);
            try {
                client.session.close();
            } catch (IOException e1) {
                // Ignore
            }
        }
    }
}

The BasicRemote acquired by the client session getBasicRemote() method sends the message in blocking mode. There’s a non-blocking implementation, called AsyncRemote, too. It’s acquired by using the getAsyncRemote() method of the client session.

We now have a server, that can receive messages from any client and forward them to all connected clients. Let’s have a look at the Java client implementation.

Java Client

For creating a Websocket client in Java, a ClientEndpoint has to be defined in a similar way as a ServerEndpoint:

@ClientEndpoint
public class RemoteWebsocketClient {

    private Session session;

    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
    }

    @OnMessage
    public void onMessage(String message) {
        System.out.println(message);
        //TODO: output message in a chat window
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {

    }

}

In this simple chat example, we only need to implement the @OnMessage annotated method. The method just outputs the received message to the console.

You will need a JSR-356 implementation on the client side, as there’s no implementation contained in the Java JRE. The standard implementation is Project Tyrus and it is used in this example.

Add the following dependencies to your client project’s POM for using Tyrus in standalone mode:

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-server</artifactId>
    <version>1.0</version>
</dependency>

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-client</artifactId>
    <version>1.0</version>
</dependency>

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-container-grizzly</artifactId>
    <version>1.0</version>
</dependency>

Let’s connect the client to the server. It’s as easy as calling connectToServer method from a ClientManager. See the full source of the ChatClient:

public class ChatClient {

    private ClientManager manager;

    public void connect(URI uri) {
        this.manager = ClientManager.createClient();
        try {
            manager.connectToServer(ChatClientEndpoint.class, uri);
        } catch (DeploymentException | IOException e) {
            System.exit(-1);
        }
    }

    public void run() {
        String msg = System.in.readLine();
        while (!"".equals(msg)) {
            manager.getSession().getBasicRemote().send(msg);
            msg = System.readLine();
        }
    }

    public void main(String[] args) {
        ChatClient cc = new ChatClient();
        cc.connect(URI.create("ws://localhost:8080/chat/service"));
        cc.run();
    }
}

The chat client connects to the server, by calling connectToServer providing a ClientEndpoint implementation class and an URI to connect to. The main loop waits for the user input to be sent to the client. The message handling is done by the ChatClientEndpoint.

Javascript

The code for a Javascript Websocket client is nearly the same as the Java ClientEndpoint. Connection is made in a browser-specific way, as Mozilla Firefox has an individual implementation named MozWebsocket instead of the standard Websocket:

var connect = function(url) {
    if ('WebSocket' in window) {
        socket = new WebSocket(url);
    } else if ('MozWebSocket' in window) {
        socket = new MozWebSocket(url);
    } 
};

Message handling is done inside the socket.onmessage method, that should be overriden. For displaying the chat messages, we create a new paragraph and append it to a div in the displaying html page.

socket.onmessage = function(msg) {
    var log = document.getElementById('log');
    var p = document.createElement('p');

    p.style.wordWrap = 'break-word';
    p.innerHTML = msg.data;
    log.appendChild(p);
}

Sending is done by using the socket’s send method:

send: function(msg) {
    socket.send(msg);
}

Why to use websockets?

The Websockets specification addresses the issues, modern web applications face using the http protocol.

With Websockets you get:

Drawbacks

The major drawback of the Websocket specification is, that there’s no application level protocol specified. That’s where we as developers are challenged to step in and develop some generic application communication protocols that fill this gap.

With a generic application protocol, the second drawback could be addressed, too: The websocket protocol does not specify a mechanism for guaranteed message delivery – a major requirement for business use.

While not unsolvable, those two issues are responsible for Webscokets not getting the momentum, they actually deserve.

Summary

In my opinion, Websockets do have really huge benefits compared to traditional http communication, and I’m looking forward to use Websockets in a commercial product in the future.

I‘d like to compare Websockets to XMLHttpRequest before it got hyped as part of AJAX: As soon as XMLHttpRequest became usable with easy and reliable to use third party libraries, the Web 2.0 started.

Websockets do need their issues worked around with some easy to use libraries, too, for eventually taking commercial client-server applications to a new level.

Useful Links

VIDEO: ISSUE 109 LAUNCH EVENT

Sponsors

  • Accenture
  • BT Code Crafters
  • Accesa
  • Bosch
  • Betfair
  • MHP
  • BoatyardX
  • .msg systems
  • Yardi
  • Colors in projects

VIDEO: ISSUE 109 LAUNCH EVENT