Below is the data that you can adapt to your GitHub repository by forking this repo. It explains the project’s motivation, architecture, setup instructions, and extension points for future maintainers.
My wife is a game designer and she asked me to create a game server for her. I started to look for a game server that could be used for her game, but I couldn't find anything ready made and had ultra-low latency capabilities since mostly they are packed with features which might never be used. So I decided to create one.
A bare-bones, scalable game server in Java designed for ultra-low latency turn-based games (like chess). This project demonstrates:
- Pure Java WebSocket implementation (no Tomcat/Jetty/Netty).
- Protobuf-based message serialization for efficient data transfer.
- Redis Pub/Sub for horizontal scaling across multiple server instances.
- Nginx/HAProxy or similar load balancer for distributing WebSocket connections.
Although chess is used as the example, the same architecture can be extended to lightweight real-time or turn-based games.
- Project Overview
- Architecture
- Features
- Prerequisites
- Setup & Installation
- Running the Server
- Testing Locally
- Scaling with Redis & Load Balancers
- Project Structure
- Extending & Customizing
- FAQ
- License
This repository contains an ultra-lightweight WebSocket server written in pure Java. It is designed for turn-based games where latency and reliability are crucial. By default, it shows how to handle chess moves, but it can be extended to any minimal real-time or turn-based gaming scenario.
Key goals:
- Minimal Dependencies: No Tomcat, no Jetty, no Spring Boot—just Java’s ServerSocket.
- Scalability: Horizontal scaling through Redis Pub/Sub.
- Efficient Data Serialization: Use of Protocol Buffers (Protobuf) to minimize message size and parsing overhead.
- Maintainability: Simple code structure that’s easy to extend for new features or different game types.
flowchart LR
C["Clients (WebSocket)"] --> LB["Load Balancer NGINX/HAProxy"]
LB --> S1["Game Server #1- Bare WebSocket-Protobuf-Redis Pub/Sub"]
LB --> S2["Game Server #2- Bare WebSocket-Protobuf-Redis Pub/Sub"]
S1 -->|Publish/Subscribe| R["Redis Pub/Sub"]
S2 -->|Publish/Subscribe| R
- Bare WebSocket Server: Handles game actions (like chess moves) via WebSocket frames (no HTTP polling).
- Protobuf Messages: Minimizes data size & improves parse speed.
- Redis Pub/Sub: Broadcasts moves between servers. This allows multiple server instances to stay in sync.
- Load Balancer: Distributes WebSocket connections evenly among all servers.
- Ultra-Lightweight Server
- No external application servers; just Java Sockets and a WebSocket handshake.
- Real-Time Communication
- Uses WebSockets for near-instant updates (no HTTP polling overhead).
- Protobuf Serialization
- Smaller message payloads than JSON or XML.
- Strongly typed schemas.
- Redis Pub/Sub for Scaling
- Multiple server instances can sync game states.
- Servers publish or subscribe to
chess_moves
channel (or any other channel you want).
- Load Balancer Integration
- Example config for Nginx to handle WebSocket connections.
- Java 8+ (or any modern JDK).
- Maven (or Gradle) for dependency management (if you choose to package your server this way).
- Protobuf Compiler (protoc)
- Install via GitHub Releases or your package manager.
- Redis (for Pub/Sub), optional but required for scaling.
- Clone the Repository
- Install Protobuf Compiler
- macOS:
brew install protobuf
- Ubuntu/Debian:
sudo apt-get install protobuf-compiler
- Windows: Download from Protobuf Releases.
- macOS:
- Compile Protobuf Schema (if you have a
.proto
file such aschess.proto
)- bash:
protoc chess.proto
- bash:
protoc chess.proto
Adjust the paths to match your project structure.
4. Build the Project
- Maven: mvn clean install
- Gradle: gradle build
Note: The simplest approach is to run your main class (e.g BareWebSocketServer
) directly from your IDE or command line after compiling.
Though, you can also package your server as a JAR file and run it as a standalone application. But I'm a fan of running it the hardway from CLI as I'm an Nvim user. I don't use Arch btw.
- Start Redis (if you want scaling)
redis-server
- Run Single Server
java -cp target/UltraLowLatencyGameServer-1.0-SNAPSHOT.jar com.example.BareWebSocketServer
This starts a WebSocket server on ws://localhost:8080
.
- Optional: Run Multiple Servers Manually
- Change the port in your second server instance (e.g., to 8090) and start it.
- Both servers connect to Redis. Moves from one server are published; the other server subscribes and broadcasts to its connected clients.
- Open Browser Console or use a WebSocket client (e.g., websocat or Postman) to connect:
const ws = new WebSocket("ws://localhost:8080");
ws.onopen = () => {
console.log("Connected");
};
ws.onmessage = (event) => {
console.log("Server says:", event.data);
};
ws.onclose = () => console.log("Disconnected");
- Send a “move” from one client, see if all other connected clients receive it in real-time.
- Redis Pub/Sub
- Each server publishes any incoming move to a Redis channel (e.g., "chess_moves").
- Each server subscribes to that same channel, receiving moves from other servers.
- Load Balancer (Nginix)
- Install & configure Nginx for WebSocket load balancing.
- Run Nginx, and direct all WebSocket connections to
ws://yourserver.com/
.
http {
upstream chess_game {
server localhost:8080;
server localhost:8085;
}
server {
listen 80;
server_name yourserver.com;
location / {
proxy_pass http://chess_game;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}
- Multiple Servers
- Start multiple instances (e.g by running
java BareWebSocketServer
) on different ports (8080, 8085, 8100…). - All instances read from the same Redis server, ensuring real-time synchronization.
- Start multiple instances (e.g by running
UltraLowLatencyGameServer/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ ├── com/example/
│ │ │ │ ├── BareWebSocketServer.java
│ │ │ │ ├── RedisHandler.java
│ │ │ │ ├── ChessMove.java (generated by Protobuf)
│ │ │ │ └── ...
│ │ └── proto/
│ │ └── chess.proto
├── pom.xml (if using Maven)
├── README.md
└── ...
chess.proto
– Defines the Protobuf message for a chess move (or any turn-based action).BareWebSocketServer.java
– The core WebSocket server implementation without any external containers.RedisHandler.java
– Subscribes/publishes moves to Redis.ChessMove.java
– Auto-generated by Protobuf compiler fromchess.proto
.
- Adding a New Game
- Create a new
.proto
schema with the required fields for your game’s events. - Generate Java classes using
protoc
. - Adjust
BareWebSocketServer
or create a new server class to handle these game events.
- Create a new
- Improving Security
- Implement TLS (using
wss://
) at the load balancer (NGINX) or within the Java server. - Add authentication tokens to WebSocket messages to identify players.
- Implement TLS (using
- State Management
- Use an in-memory or Redis store to keep track of each game’s state (e.g., board positions, turn timers).
- High Availability
- Deploy servers behind a Kubernetes or Docker Swarm cluster.
- Use a managed Redis service (e.g., AWS ElastiCache).
- Why not use HTTP Polling?
- WebSockets provide lower overhead and real-time updates. HTTP Polling is inefficient and increases latency.
- Why Protobuf instead of JSON?
- Smaller payloads and faster parsing. In real-time games, every millisecond counts.
- Can I run more than two servers?
- Absolutely. Just add more servers (S3, S4, …), all subscribing to the same Redis Pub/Sub channel.
- How to handle concurrency or locking on game state?
- Typically, you’ll maintain a consistent game state in a shared store (Redis, database) or implement row-level locks if needed. For simple turn-based games, a single server thread is often sufficient.
- Is it production-ready?
- This project is a foundation. You should add error handling, security, and robust load testing before going live.
MIT License – Feel free to modify and distribute. Contributions are welcome!
Happy coding and scaling! If you have any questions, open an issue. We’d love to hear how you’re using this for your own game projects.
I would keep updating this project with new features and improvements. If you have any suggestions, feel free to open an issue or a pull request. If you want to use this project please give me a star and fork this project. It will help me a lot. Thank you for reading this README.md file. Have a nice day! 😊