WebSocket Programming with Java

Javier Gonzalez
The Startup

--

A Websocket allows creating a communication channel between a client and a server. In particular, a communication channel that uses the WebSocket protocol as a communication protocol. The WebSocket protocol is compatible with the HTTP protocol (yes, the one used to connect web browsers and web servers). However, it has exceptional improvements: (1) lower overhead than HTTP and (2) bi-directional web communication.

Figure 1. Traditional HTTP communication vs. WebSocket

Traditional Web communication using the HTTP protocol works as follows:

  • First, a client (usually a web browser) has to connect to the server;
  • then, the client sends a request for a resource (such as a request for a webpage);
  • after that, the server responds, and
  • closes the communication channel.

On the other hand, WebSocket works as follows:

  • keep the connection open; moreover
  • both client and server can make requests and send responses.

There are diverse Java libraries that allow developers to create Websocket based applications in Java. Either for Java application that will have the role of client and connect to existing Web servers. Or, Java applications that will connect with a server also wrote in Java. We will explore the former — a Java client to connect to an existing server.

Getting Started

First, we need a library that helps us to deal with the details. I am showing you examples using Eclipse Tyrus — an open-source API for the easy development of WebSocket applications. Therefore, we need to add to our project the following dependencies: (1) tyrus.client, (2) tyrus.server, and since we are building a standalone application, we need also help with a container, (3) tyrus.container.grizzly. Click the links and get the dependencies configuration (Maven, Gradle, etc.), or get the bundles with all the JAR files you need. Up to you. Set up your project and then move forward with the coding part.

Server

The API allows us to work using Java Annotations or “traditional” API interfaces. The example below follows the annotations approach. Arguably, using annotations provides better information about classes and the method’s responsibilities. Let us start with the server. It is shown in Figure 2. Important elements:

  1. Import the package — tyrus.server. We need the class Server.
  2. Create a Server object. Arguments for the constructor: hostName (localhost in this example), the port in which the server will run, the root path for the server app, and the important one, the class to handle the server work. It can be a class annotated with ServerEndpoint, (as our example will) or a class implementing ServerApplicationConfigor, a class extending ServerEndpointConfig.
  3. Run the start() method in the server object, and that is all.
Figure 2. ChatServer.java

ServerEndpoint

ServerEndPoint is a class-level annotation that declares that the class it decorates is a WebSocket endpoint deployed and made available in a WebSocket server. Our ServerEndPoint is as shown in Figure 3. Important elements:

  1. The class-level annotation ServerEndpoint specifies the URL in which the endpoint will be published (in conjunction with the hostName, port, and path defined before). In this case, our example will be running as localhost:8025/project/app.
  2. The rest of the class is pretty straightforward to read: methods that will be called automatically when a connection opens, onOpen(), a message is received, onMessage(), or the connection closes, onClose().

In the example, we are working with text messages. But binary is also supported. This server prints and returns (to the client) the same message that it receives. Input as parameter and output as a return value. Simple, right?

Figure 3. ChatServerEndpoint.java

Client

Now, it is time to create a client to connect with our server. Figure 3 shows the critical elements:

  1. As can imagine, our class need to be annotated, now as a ClientEndpoint
  2. Line 36 and 39 do the magic. We create a ClientManager and then ask it to connect the supplied annotated endpoint (our client) and a server specified by a URI.
  3. Once the connection is established, the logic is similar to the one in the server: methods that will be called automatically when a connection opens, onOpen(), a message is received, onMessage(), or the connection closes, onClose().
Figure 4. ChatClientEndpoint.java

What is the client doing? First, when the connection opens, the client sends a message to the server using session.getBasicRemote().sendText() –Line 11. The server receives the message and answers with the same string. Then, the method onMessage() will run in the client. Just for fun, our client in the method onMessage() is reading a string from the user’s keyboard (using System.in) and sending that string to our server. At this point, our application consists of the methods onMessage() being executed on the client and the server sides.

Source Code

The complete source code for the described example is available on my GitHub. Explore the details there and happy coding.

Challenge

Now that we have a vanilla implementation of WebSockets, How hard could it be to add some decoration here and create a ChatApp with a friendly GUI for the client? 🤔

There are diverse uses of WebSockets. One of them is accessing Emotiv Cortex API data streams — Emotiv is a wireless brain measuring device and software solution. How to do that? That is a topic for another publication.

I regularly write about Software & AI — if you would like to read my future posts, then please give me a follow, subscribe, or share a coffee.

--

--

Javier Gonzalez
The Startup

Specialized in human-centered, self-adaptive intelligent systems and passionate about teaching emerging technologies.