Mercurial
diff seobeo/docs/web_socket_client.md @ 120:cbbf78b17cfa
[Seobeo][Websocket] Created Web socket client logic.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Thu, 08 Jan 2026 03:19:59 -0800 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/seobeo/docs/web_socket_client.md Thu Jan 08 03:19:59 2026 -0800 @@ -0,0 +1,270 @@ +# 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