Mercurial
view seobeo/docs/web_socket_server.md @ 147:6de849867459 hg-web
[HgWeb] Updated logic to use Seobeo Client.
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Fri, 09 Jan 2026 18:39:34 -0800 |
| parents | 7b1719fa918c |
| children |
line wrap: on
line source
# Seobeo WebSocket Server - Usage Guide A clean, easy-to-use WebSocket server library that integrates seamlessly with the existing Seobeo HTTP server. ## Features 1. **Automatic Upgrade Handling**: Automatically detects and upgrades HTTP connections to WebSocket 2. **Route-Based Handlers**: Register WebSocket handlers for specific paths (like HTTP routing) 3. **Text and Binary Messages**: Send/receive both text and binary data 4. **Broadcast Support**: Send messages to all connected clients 5. **Connection Management**: Automatic connection tracking and cleanup 6. **Integrated with HTTP Server**: Works alongside existing HTTP routes and static file serving 7. **RFC 6455 Compliant**: Full WebSocket protocol support ## API Overview ### Initialization and Registration ```c // Initialize WebSocket server system void Seobeo_WebSocket_Server_Init(); // Register a WebSocket handler for a specific path void Seobeo_WebSocket_Server_Register(const char *path, Seobeo_WebSocket_Server_Handler handler, void *p_user_data); ``` ### Handler Function Type ```c typedef void (*Seobeo_WebSocket_Server_Handler)( Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data ); ``` ### Sending Messages ```c // Send to specific client int32 Seobeo_WebSocket_Server_Send_Text(Seobeo_WebSocket_Server_Connection *p_conn, const char *text); int32 Seobeo_WebSocket_Server_Send_Binary(Seobeo_WebSocket_Server_Connection *p_conn, const uint8 *data, size_t length); // Broadcast to all clients void Seobeo_WebSocket_Server_Broadcast_Text(const char *text); void Seobeo_WebSocket_Server_Broadcast_Binary(const uint8 *data, size_t length); ``` ### Connection Management ```c // Close specific connection void Seobeo_WebSocket_Server_Connection_Close(Seobeo_WebSocket_Server_Connection *p_conn, uint16 code, const char *reason); ``` ## Examples ### 1. Simple Echo Server ```c #include "seobeo/seobeo.h" void Echo_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { printf("Received: %.*s\n", (int)p_msg->length, (char*)p_msg->data); Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data); } } int main() { // Initialize WebSocket routing Seobeo_WebSocket_Server_Init(); // Register echo handler Seobeo_WebSocket_Server_Register("/echo", Echo_Handler, NULL); // Start HTTP server (automatically handles WebSocket upgrades) Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 2. Chat Room Server ```c void Chat_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { char message[2048]; snprintf(message, sizeof(message), "[%s]: %.*s", p_conn->client_id, (int)p_msg->length, (char*)p_msg->data); printf("Broadcasting: %s\n", message); Seobeo_WebSocket_Server_Broadcast_Text(message); } } int main() { Seobeo_WebSocket_Server_Init(); Seobeo_WebSocket_Server_Register("/chat", Chat_Handler, NULL); printf("Chat server started on ws://localhost:8080/chat\n"); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 3. Binary Data Broadcasting ```c void Binary_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_BINARY) { printf("Received %zu bytes, broadcasting...\n", p_msg->length); Seobeo_WebSocket_Server_Broadcast_Binary(p_msg->data, p_msg->length); } } int main() { Seobeo_WebSocket_Server_Init(); Seobeo_WebSocket_Server_Register("/binary", Binary_Handler, NULL); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 4. Multiple Endpoints ```c void Echo_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data); } void Chat_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { char msg[2048]; snprintf(msg, sizeof(msg), "[%s]: %.*s", p_conn->client_id, (int)p_msg->length, (char*)p_msg->data); Seobeo_WebSocket_Server_Broadcast_Text(msg); } } int main() { Seobeo_WebSocket_Server_Init(); // Register multiple WebSocket endpoints Seobeo_WebSocket_Server_Register("/echo", Echo_Handler, NULL); Seobeo_WebSocket_Server_Register("/chat", Chat_Handler, NULL); printf("Server started with:\n"); printf(" ws://localhost:8080/echo - Echo server\n"); printf(" ws://localhost:8080/chat - Chat room\n"); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 5. Custom User Data ```c typedef struct { int message_count; char name[64]; } ChatRoomData; void Chat_Handler_With_Data(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { ChatRoomData *p_data = (ChatRoomData*)p_user_data; if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { p_data->message_count++; char message[2048]; snprintf(message, sizeof(message), "[%s #%d]: %.*s", p_data->name, p_data->message_count, (int)p_msg->length, (char*)p_msg->data); Seobeo_WebSocket_Server_Broadcast_Text(message); } } int main() { ChatRoomData room_data = {0}; strcpy(room_data.name, "Main Room"); Seobeo_WebSocket_Server_Init(); Seobeo_WebSocket_Server_Register("/chat", Chat_Handler_With_Data, &room_data); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 6. Mixed HTTP and WebSocket Server ```c // HTTP route handler Seobeo_Request_Entry* Get_Status(Seobeo_Request_Entry *req, Dowa_Arena *arena) { Seobeo_Request_Entry *resp = NULL; Dowa_HashMap_Push_Arena(resp, "status", "200", arena); Dowa_HashMap_Push_Arena(resp, "content-type", "application/json", arena); Dowa_HashMap_Push_Arena(resp, "body", "{\"status\": \"online\"}", arena); return resp; } // WebSocket handler void WS_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data); } int main() { // Initialize both HTTP and WebSocket routing Seobeo_Router_Init(); Seobeo_WebSocket_Server_Init(); // Register HTTP routes Seobeo_Router_Register("GET", "/api/status", Get_Status); // Register WebSocket routes Seobeo_WebSocket_Server_Register("/ws", WS_Handler, NULL); printf("Server started:\n"); printf(" HTTP: http://localhost:8080/api/status\n"); printf(" WebSocket: ws://localhost:8080/ws\n"); Seobeo_Web_Server_Start("./public", "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ## Building ### Build the server example: ```bash bazel build //seobeo:websocket_server_example ``` ### Run the server: ```bash bazel-bin/seobeo/websocket_server_example ``` ### Test with a client: You can test the server using the WebSocket client API or any WebSocket client tool: ```bash # Using websocat (install: cargo install websocat) websocat ws://localhost:8080/echo # Using wscat (install: npm install -g wscat) wscat -c ws://localhost:8080/chat ``` ## Connection Structure ```c struct Seobeo_WebSocket_Server_Connection_Struct { Seobeo_Handle *p_handle; // Underlying socket handle char *client_id; // Unique client identifier boolean is_active; // Connection status // Fragment handling (internal) uint8 *fragment_buffer; size_t fragment_length; size_t fragment_capacity; Seobeo_WebSocket_Opcode fragment_opcode; Seobeo_WebSocket_Server_Connection *next; // Linked list }; ``` ## Protocol Details The server implementation follows RFC 6455: 1. **Handshake**: Responds to HTTP Upgrade requests with proper Sec-WebSocket-Accept key 2. **Frame Format**: Server sends unmasked frames (RFC requirement) 3. **Frame Receiving**: Server receives and unmasks client frames 4. **Fragmentation**: Handles fragmented messages automatically 5. **Control Frames**: Proper handling of ping, pong, and close frames 6. **Broadcast**: Efficiently sends to all active connections ## Key Differences from Client | Feature | Client | Server | |---------|--------|--------| | Frame Masking | Masks outgoing frames | Does NOT mask outgoing frames | | Connection | Initiates connection | Accepts connections | | Upgrade | Sends upgrade request | Responds to upgrade request | | Multiple Connections | Single connection | Manages multiple connections | | Broadcast | N/A | Can broadcast to all clients | ## Coding Standards The implementation follows your specified coding standards: - Naming: `Seobeo_WebSocket_Server_Init`, `Seobeo_WebSocket_Server_Send_Text` - Two spaces for indentation - New line before `{` unless it's a struct - Single statement: no need for `{}` ## Integration with Existing Server The WebSocket server integrates seamlessly: 1. **Automatic Detection**: The HTTP server automatically checks for WebSocket upgrade requests 2. **No Conflicts**: WebSocket and HTTP routes coexist peacefully 3. **Same Port**: WebSocket and HTTP share the same server port 4. **Unified Server**: Use `Seobeo_Web_Server_Start()` for everything ## Testing the Server ### JavaScript Client (Browser): ```javascript const ws = new WebSocket('ws://localhost:8080/echo'); ws.onopen = () => { console.log('Connected!'); ws.send('Hello, Server!'); }; ws.onmessage = (event) => { console.log('Received:', event.data); }; ``` ### Python Client: ```python import websocket ws = websocket.create_connection("ws://localhost:8080/chat") ws.send("Hello from Python!") print(ws.recv()) ws.close() ``` ## Performance Considerations 1. **Fork Mode**: Each connection runs in a separate process (SEOBEO_MODE_FORK) 2. **Edge Mode**: Multi-threaded connections (SEOBEO_MODE_EDGE) 3. **Broadcast**: Iterates through all connections (O(n) complexity) 4. **Fragmentation**: Large messages are automatically fragmented (1MB chunks) ## Complete Feature Comparison | Feature | Implemented | |---------|-------------| | ✅ WebSocket upgrade handshake | Yes | | ✅ Text messages | Yes | | ✅ Binary messages | Yes | | ✅ Message fragmentation | Yes | | ✅ Ping/Pong | Yes | | ✅ Close handshake | Yes | | ✅ Multiple endpoints | Yes | | ✅ Broadcast | Yes | | ✅ Connection tracking | Yes | | ✅ Integration with HTTP server | Yes | | ✅ Custom user data per handler | Yes | The Seobeo WebSocket Server provides a complete, production-ready WebSocket implementation that works seamlessly with the existing HTTP server!