---
title: "Server-Client (Networking)"
source: "https://cheerpj.com/docs/tutorials/serverclient"
---

# Server-Client (Networking)

Communication between two Java apps using CheerpJ and Tailscale.

This tutorial runs two Java applications in the browser with CheerpJ, a server and a client, and connects them over TCP with `java.net.ServerSocket` and `java.net.Socket`. Browsers do not give web pages access to TCP sockets, so the two applications connect through a Tailscale network.

For how CheerpJ and Tailscale work together, see the [Networking guide](https://cheerpj.com/docs/guides/Networking.md). The finished project is in the `examples/Server-Client` directory of the [cheerpj-meta repository](https://github.com/leaningtech/cheerpj-meta).

![A server app and a client app, each running in CheerpJ in its own browser tab, using java.net.ServerSocket and java.net.Socket, connected over WebSockets through the Tailscale VPN (WireGuard over WebSockets)](https://cheerpj.com/docs/cheerpj3/assets/Tailscale_P2P.png)

## Prerequisites

- A text editor to create and edit an HTML file
- A local HTTP server that supports Range requests, such as `npx http-server`
- A modern browser such as Chrome, Edge, Firefox or Safari
- A Tailscale account (see [step 2](#2-tailscale))

## 1. The Java applications

The example is a chat room: a Java server application and a Java client application that exchange messages over sockets. It is based on a [TechVidvan](https://techvidvan.com/tutorials/) tutorial, which [explains the source code](https://techvidvan.com/tutorials/java-chat-application/).

Both applications run in the browser with CheerpJ, with no Java installation.

![Client Server](https://cheerpj.com/docs/cheerpj3/assets/client-server.png)

## 2. Tailscale

As the [Networking guide](https://cheerpj.com/docs/guides/Networking.md) explains, CheerpJ supports networking other than HTTP(S), such as TCP and UDP sockets, through Tailscale. Tailscale is a VPN based on WireGuard, which CheerpJ reaches over WebSockets.

### 2.1 Setting up Tailscale

Create a Tailscale network and connect both Java applications to it as _nodes_. In Tailscale terminology, a node is a combination of a user and a device connected to the network.

1. Create a Tailscale account and [log in](https://login.tailscale.com/). Creating an account creates a network (a _tailnet_).
2. Generate two auth keys, one for each application, in the [Tailscale admin console](https://login.tailscale.com/admin/settings/keys), or one reusable key. Keep them for later: the applications use them to join the tailnet.

> **Tailscale auth keys**
>
> Choose the options in the Tailscale keys menu that suit you. Each time a page starts CheerpJ with a key it adds a node to the tailnet. To keep within your Tailscale device quota, use ephemeral keys or remove unused devices from the admin console.

## 3. Setting up the project

Create a project directory with two subdirectories, one for the server and one for the client:

1. Create the project directory tree:

```bash
mkdir -p ServerClientTutorial/{Server,Client}
```

2. Put each application’s JAR in its directory:

   - [Download the Server JAR](https://cheerpj.com/docs/cheerpj3/tutorials/Server.jar)
   - [Download the Client JAR](https://cheerpj.com/docs/cheerpj3/tutorials/Client.jar)

3. Create an HTML file in each subdirectory: `server.html` in `Server` and `client.html` in `Client`. The project tree looks like this:

```plaintext
└──ServerClientTutorial
    ├── Server
    │   ├── Server.jar
    │   └── server.html
    └── Client
        ├── Client.jar
        └── client.html
```

### 3.1 The Server application

1. Add this code to `server.html`:

`server.html`

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Server</title>
    <script src="https://cjrtnc.leaningtech.com/5.0/loader.js"></script>
  </head>
  <body>
    <input type="text" id="ip" />
    <script>
      (async function () {
        await cheerpjInit({
          tailscaleAuthKey: "PasteYourKeyHere",
          tailscaleIpCb: (ip) => {
            let el = document.querySelector("#ip");
            el.value = ip;
          },
        });
        cheerpjCreateDisplay(800, 600);
        await cheerpjRunJar("/app/Server.jar");
      })();
    </script>
  </body>
</html>
```

**What is happening here?**

- The `<script>` tag in the `<head>` loads CheerpJ.
- [`cheerpjInit`](https://cheerpj.com/docs/reference/cheerpjInit.md) initialises CheerpJ. The [`tailscaleAuthKey`](https://cheerpj.com/docs/reference/cheerpjInit.md#tailscaleauthkey) option passes the auth key that the application uses to join the tailnet.
- [`tailscaleIpCb`](https://cheerpj.com/docs/reference/cheerpjInit.md#tailscaleipcb) is called with the application’s IP address on the tailnet once it is connected. The page writes it into the input field so you can copy it.
- [`cheerpjCreateDisplay`](https://cheerpj.com/docs/reference/cheerpjCreateDisplay.md) creates an 800x600 display that holds all Java windows.
- [`cheerpjRunJar`](https://cheerpj.com/docs/reference/cheerpjRunJar.md) runs the server application.
- `/app/` is the [virtual file system](https://cheerpj.com/docs/explanation/File-System-support.md) mount point for the root of the web server the page is loaded from.

2. Replace _“PasteYourKeyHere”_ with the first auth key.
3. Serve the page with an HTTP server started **inside** the `Server` directory:

```bash
cd ServerClientTutorial/Server
npx http-server -p 8080
```

4. Open `http://127.0.0.1:8080/server.html` in a browser tab.
5. CheerpJ shows its loading animation, then the server application starts.
6. Once the server is connected to the tailnet, its IP address appears in the field above the display. Keep it: the client needs it to connect. The address is also listed in the [Tailscale admin console](https://login.tailscale.com/admin/machines).

### 3.2 The Client application

1. Add this code to `client.html`:

`client.html`

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Client</title>
    <script src="https://cjrtnc.leaningtech.com/5.0/loader.js"></script>
  </head>
  <body>
    <input type="text" id="ip" />
    <script>
      async function start(ip) {
        await cheerpjInit({
          tailscaleAuthKey: "PasteYourKeyHere",
        });
        cheerpjCreateDisplay(800, 600);
        await cheerpjRunJar("/app/Client.jar", ip);
      }
      let el = document.querySelector("#ip");
      el.addEventListener("keydown", (e) => {
        if (e.key == "Enter") {
          start(el.value);
        }
      });
    </script>
  </body>
</html>
```

**What is happening here?**

- The page waits for you to type the server’s IP address in the input field and press Enter, then starts CheerpJ.
- The second argument of [`cheerpjRunJar`](https://cheerpj.com/docs/reference/cheerpjRunJar.md) is passed to the Java `main` method in `args`. Here it is the server’s Tailscale IP address, which the client connects to.

2. Replace _“PasteYourKeyHere”_ with the second auth key.
3. Serve the page with an HTTP server started **inside** the `Client` directory, on a different port from the server’s:

```bash
cd ServerClientTutorial/Client
npx http-server -p 8081
```

4. Open `http://127.0.0.1:8081/client.html` in another browser tab.
5. Paste the server’s IP address in the input field and press Enter.
6. CheerpJ shows its loading animation, then the client application starts and connects to the server.

## 4. Final test

With both applications running, enter a username and connect in each of them. Then send messages from one application to the other.

![Server Browser](https://cheerpj.com/docs/cheerpj3/assets/server-browser.png)

![Client Browser](https://cheerpj.com/docs/cheerpj3/assets/client-browser.png)

[View full source code on GitHub](https://github.com/leaningtech/cheerpj-meta/tree/main/examples/Server-Client)

## Credits

The Java applications used in this tutorial belong to [TechVidvan](https://techvidvan.com/tutorials/). Their [tutorial](https://techvidvan.com/tutorials/java-chat-application/) includes the source code. The applications have been lightly edited for this tutorial.

## Further reading

- [Networking guide](https://cheerpj.com/docs/guides/Networking.md)
- [Runtime API reference](https://cheerpj.com/docs/reference.md)
