Skip to content

AhmedSobhy01/websocket-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WebSocket Server

A WebSocket server written in C++17 from scratch, with no external dependencies beyond OpenSSL (used only for SHA-1 during the handshake). It implements the RFC 6455 protocol directly on top of POSIX sockets.

Features

  • Accepts WebSocket connections over TCP
  • Performs the HTTP Upgrade handshake
  • Decodes and encodes WebSocket frames (text, binary, ping/pong, close, continuation)
  • Handles fragmented messages
  • Manages multiple concurrent connections using poll()
  • Responds to ping frames with pong
  • Handles graceful close handshake with proper close codes
  • Shuts down cleanly on SIGINT / SIGTERM

Architecture

The server uses a single-threaded event loop with poll() for I/O multiplexing. Each connection moves through a state machine:

CONNECTING → OPEN → CLOSING → CLOSED

Components:

  • Server: Manages the listen socket and connection pool. Runs the event loop and accepts new connections.
  • Connection: Handles per-client state, processes handshakes, and manages frame I/O. Enforces protocol rules (masking, fragmentation, close handshake).
  • FrameHandler: Encodes and decodes WebSocket frames per RFC 6455. Handles payload length encoding (7-bit, 16-bit, 64-bit) and masking/unmasking.
  • Handshake: Parses HTTP Upgrade requests and generates Sec-WebSocket-Accept responses.
  • TcpSocket: Thin wrapper around POSIX socket APIs.

Requirements

  • Linux (uses POSIX sockets and poll())
  • g++ with C++17 support

Build

make

This produces the ws_server binary in the project root.

To remove build artifacts:

make clean

Run

./ws_server

The server listens on port 9002 by default (configured in main.cpp).

Testing

Browser:

const ws = new WebSocket("ws://localhost:9002");
ws.onopen = () => {
    console.log("Connected");
    ws.send("hello");
};
ws.onmessage = (e) => console.log("Received:", e.data);
ws.onclose = (e) => console.log("Closed:", e.code, e.reason);

Command line (wscat):

# Install wscat
npm install -g wscat

# Connect
wscat -c ws://localhost:9002

Protocol Compliance

Implemented:

  • HTTP Upgrade handshake with Sec-WebSocket-Accept validation
  • Frame encoding/decoding (all opcodes: text, binary, close, ping, pong, continuation)
  • Client-to-server masking enforcement
  • Message fragmentation and reassembly
  • Close handshake with status codes (1000-1011)
  • Ping/pong keep-alive mechanism
  • 16 MB max payload size per frame

Not implemented:

  • WebSocket extensions (per-message compression, multiplexing)
  • TLS/SSL (wss:// connections)
  • Subprotocol negotiation (Sec-WebSocket-Protocol)
  • Origin validation
  • UTF-8 validation for text frames

Limitations

  • Single-threaded: All connections share one event loop. No parallel processing.
  • Echo/log only: Received messages are printed to stdout, not broadcast or persisted.
  • No TLS: Runs plain ws:// only. No wss:// support.
  • No connection broadcasting: Messages aren't forwarded between clients.
  • No authentication: All connections are accepted without validation.
  • Fixed buffer size: 4 KB recv buffer may require multiple reads for large frames.

License

This project is licensed under the MIT License. See LICENSE for details.

About

A lightweight WebSocket server written in C++ from scratch, implementing RFC 6455 with no dependencies beyond OpenSSL

Topics

Resources

License

Stars

Watchers

Forks

Contributors