view seobeo/docs/web_socket_client.md @ 126:e7899c93da77

Remove playground.
author June Park <parkjune1995@gmail.com>
date Thu, 08 Jan 2026 18:03:34 -0800
parents cbbf78b17cfa
children
line wrap: on
line source

# Seobeo WebSocket Client - Usage Guide

A clean, easy-to-use WebSocket client library following RFC 6455.

## Features

1. **WebSocket Protocol Support**: Full RFC 6455 WebSocket implementation
2. **Text and Binary Messages**: Send/receive both text and binary data
3. **Automatic Ping/Pong**: Automatic pong responses to ping frames
4. **Message Fragmentation**: Handles fragmented messages automatically
5. **Secure WebSocket**: Supports both `ws://` and `wss://` (WebSocket over TLS)
6. **Clean API**: Simple, intuitive API following seobeo coding standards

## API Overview

### Core Functions

```c
// Connect to WebSocket server
Seobeo_WebSocket *Seobeo_WebSocket_Connect(const char *url);

// Send messages
int32 Seobeo_WebSocket_Send_Text(Seobeo_WebSocket *p_ws, const char *text);
int32 Seobeo_WebSocket_Send_Binary(Seobeo_WebSocket *p_ws, const uint8 *data, size_t length);

// Send control frames
int32 Seobeo_WebSocket_Send_Ping(Seobeo_WebSocket *p_ws, const char *payload);
int32 Seobeo_WebSocket_Send_Pong(Seobeo_WebSocket *p_ws, const char *payload);

// Receive messages
Seobeo_WebSocket_Message *Seobeo_WebSocket_Receive(Seobeo_WebSocket *p_ws);

// Close connection
int32 Seobeo_WebSocket_Close(Seobeo_WebSocket *p_ws, uint16 code, const char *reason);

// Clean up
void Seobeo_WebSocket_Message_Destroy(Seobeo_WebSocket_Message *p_msg);
void Seobeo_WebSocket_Destroy(Seobeo_WebSocket *p_ws);
```

### Message Opcodes

```c
typedef enum {
  SEOBEO_WS_OPCODE_CONTINUATION = 0x0,  // Continuation frame
  SEOBEO_WS_OPCODE_TEXT = 0x1,          // Text message
  SEOBEO_WS_OPCODE_BINARY = 0x2,        // Binary message
  SEOBEO_WS_OPCODE_CLOSE = 0x8,         // Close connection
  SEOBEO_WS_OPCODE_PING = 0x9,          // Ping frame
  SEOBEO_WS_OPCODE_PONG = 0xA           // Pong frame
} Seobeo_WebSocket_Opcode;
```

### Connection States

```c
typedef enum {
  SEOBEO_WS_STATE_CONNECTING = 0,  // Handshake in progress
  SEOBEO_WS_STATE_OPEN,            // Connection established
  SEOBEO_WS_STATE_CLOSING,         // Close handshake initiated
  SEOBEO_WS_STATE_CLOSED           // Connection closed
} Seobeo_WebSocket_State;
```

## Examples

### 1. Simple Text Echo

```c
// Connect to WebSocket server
Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://echo.websocket.org");
if (!p_ws)
{
  printf("Failed to connect\n");
  return;
}

// Send text message
const char *message = "Hello, WebSocket!";
Seobeo_WebSocket_Send_Text(p_ws, message);

// Receive echo response
Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
if (p_msg && p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
{
  printf("Received: %.*s\n", (int)p_msg->length, (char*)p_msg->data);
  Seobeo_WebSocket_Message_Destroy(p_msg);
}

// Close connection
Seobeo_WebSocket_Close(p_ws, 1000, "Normal closure");
Seobeo_WebSocket_Destroy(p_ws);
```

### 2. Binary Data Transfer

```c
Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com/data");

// Send binary data
uint8 data[] = {0x01, 0x02, 0x03, 0xAA, 0xBB, 0xCC};
Seobeo_WebSocket_Send_Binary(p_ws, data, sizeof(data));

// Receive binary response
Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
if (p_msg && p_msg->opcode == SEOBEO_WS_OPCODE_BINARY)
{
  printf("Received %zu bytes\n", p_msg->length);
  // Process binary data...
  Seobeo_WebSocket_Message_Destroy(p_msg);
}

Seobeo_WebSocket_Destroy(p_ws);
```

### 3. Chat Application

```c
Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://chat.example.com");

// Send chat message
Seobeo_WebSocket_Send_Text(p_ws, "Hello everyone!");

// Continuous receive loop
while (1)
{
  Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
  if (p_msg)
  {
    if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
    {
      printf("Chat: %.*s\n", (int)p_msg->length, (char*)p_msg->data);
    }
    Seobeo_WebSocket_Message_Destroy(p_msg);
  }

  usleep(10000);  // 10ms sleep to avoid busy waiting
}

Seobeo_WebSocket_Destroy(p_ws);
```

### 4. Ping/Pong Keep-Alive

```c
Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://api.example.com");

// Send ping to keep connection alive
Seobeo_WebSocket_Send_Ping(p_ws, "keep-alive");

// Server will automatically receive pong responses
// (pong responses are handled internally)

Seobeo_WebSocket_Destroy(p_ws);
```

### 5. Handling Different Message Types

```c
Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com");

while (1)
{
  Seobeo_WebSocket_Message *p_msg = Seobeo_WebSocket_Receive(p_ws);
  if (p_msg)
  {
    switch (p_msg->opcode)
    {
      case SEOBEO_WS_OPCODE_TEXT:
        printf("Text: %.*s\n", (int)p_msg->length, (char*)p_msg->data);
        break;

      case SEOBEO_WS_OPCODE_BINARY:
        printf("Binary: %zu bytes\n", p_msg->length);
        break;

      default:
        printf("Unknown opcode: 0x%X\n", p_msg->opcode);
        break;
    }

    Seobeo_WebSocket_Message_Destroy(p_msg);
  }

  usleep(10000);
}

Seobeo_WebSocket_Destroy(p_ws);
```

### 6. Graceful Shutdown

```c
Seobeo_WebSocket *p_ws = Seobeo_WebSocket_Connect("wss://example.com");

// Do work...

// Close with custom status code and reason
Seobeo_WebSocket_Close(p_ws, 1000, "Client shutting down");
Seobeo_WebSocket_Destroy(p_ws);
```

## WebSocket Close Codes

Common close status codes (RFC 6455):

- **1000**: Normal closure
- **1001**: Going away (e.g., server shutdown, browser navigation)
- **1002**: Protocol error
- **1003**: Unsupported data type
- **1006**: Abnormal closure (no close frame received)
- **1007**: Invalid frame payload data
- **1008**: Policy violation
- **1009**: Message too big
- **1010**: Mandatory extension missing
- **1011**: Internal server error

## Building

### Build the library:
```bash
bazel build //seobeo:seobeo_client
```

### Build and run the WebSocket test:
```bash
bazel test //seobeo:seobeo_websocket_test
```

## Message Structure

```c
typedef struct {
  Seobeo_WebSocket_Opcode opcode;  // Message type
  uint8  *data;                    // Message payload
  size_t  length;                  // Payload length
  boolean is_final;                // Final fragment flag
} Seobeo_WebSocket_Message;
```

## Protocol Details

The implementation follows RFC 6455:

1. **Handshake**: HTTP Upgrade request with `Sec-WebSocket-Key`
2. **Frame Format**: Proper FIN, opcode, mask, and payload length handling
3. **Masking**: All client-to-server frames are masked (required by RFC)
4. **Fragmentation**: Handles fragmented messages across multiple frames
5. **Control Frames**: Proper handling of ping, pong, and close frames
6. **TLS Support**: Supports secure WebSocket (wss://) via OpenSSL

## Coding Standards

The implementation follows your specified coding standards:
- Naming: `Seobeo_WebSocket_Connect`, `Seobeo_WebSocket_Send_Text`
- Two spaces for indentation
- New line before `{` unless it's a struct
- Single statement: no need for `{}`

## Features

✅ WebSocket handshake (HTTP Upgrade)
✅ Text and binary message support
✅ Automatic masking for client frames
✅ Message fragmentation handling
✅ Ping/Pong frames
✅ Close handshake
✅ TLS/SSL support (wss://)
✅ Non-blocking receive
✅ Proper memory management with arenas