comparison seobeo/docs/web_socket_server.md @ 121:7b1719fa918c

[Seobeo] Added web socket server.
author June Park <parkjune1995@gmail.com>
date Thu, 08 Jan 2026 06:45:10 -0800
parents
children
comparison
equal deleted inserted replaced
120:cbbf78b17cfa 121:7b1719fa918c
1 # Seobeo WebSocket Server - Usage Guide
2
3 A clean, easy-to-use WebSocket server library that integrates seamlessly with the existing Seobeo HTTP server.
4
5 ## Features
6
7 1. **Automatic Upgrade Handling**: Automatically detects and upgrades HTTP connections to WebSocket
8 2. **Route-Based Handlers**: Register WebSocket handlers for specific paths (like HTTP routing)
9 3. **Text and Binary Messages**: Send/receive both text and binary data
10 4. **Broadcast Support**: Send messages to all connected clients
11 5. **Connection Management**: Automatic connection tracking and cleanup
12 6. **Integrated with HTTP Server**: Works alongside existing HTTP routes and static file serving
13 7. **RFC 6455 Compliant**: Full WebSocket protocol support
14
15 ## API Overview
16
17 ### Initialization and Registration
18
19 ```c
20 // Initialize WebSocket server system
21 void Seobeo_WebSocket_Server_Init();
22
23 // Register a WebSocket handler for a specific path
24 void Seobeo_WebSocket_Server_Register(const char *path,
25 Seobeo_WebSocket_Server_Handler handler, void *p_user_data);
26 ```
27
28 ### Handler Function Type
29
30 ```c
31 typedef void (*Seobeo_WebSocket_Server_Handler)(
32 Seobeo_WebSocket_Server_Connection *p_conn,
33 Seobeo_WebSocket_Message *p_msg,
34 void *p_user_data
35 );
36 ```
37
38 ### Sending Messages
39
40 ```c
41 // Send to specific client
42 int32 Seobeo_WebSocket_Server_Send_Text(Seobeo_WebSocket_Server_Connection *p_conn,
43 const char *text);
44 int32 Seobeo_WebSocket_Server_Send_Binary(Seobeo_WebSocket_Server_Connection *p_conn,
45 const uint8 *data, size_t length);
46
47 // Broadcast to all clients
48 void Seobeo_WebSocket_Server_Broadcast_Text(const char *text);
49 void Seobeo_WebSocket_Server_Broadcast_Binary(const uint8 *data, size_t length);
50 ```
51
52 ### Connection Management
53
54 ```c
55 // Close specific connection
56 void Seobeo_WebSocket_Server_Connection_Close(Seobeo_WebSocket_Server_Connection *p_conn,
57 uint16 code, const char *reason);
58 ```
59
60 ## Examples
61
62 ### 1. Simple Echo Server
63
64 ```c
65 #include "seobeo/seobeo.h"
66
67 void Echo_Handler(Seobeo_WebSocket_Server_Connection *p_conn,
68 Seobeo_WebSocket_Message *p_msg, void *p_user_data)
69 {
70 if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
71 {
72 printf("Received: %.*s\n", (int)p_msg->length, (char*)p_msg->data);
73 Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data);
74 }
75 }
76
77 int main()
78 {
79 // Initialize WebSocket routing
80 Seobeo_WebSocket_Server_Init();
81
82 // Register echo handler
83 Seobeo_WebSocket_Server_Register("/echo", Echo_Handler, NULL);
84
85 // Start HTTP server (automatically handles WebSocket upgrades)
86 Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0);
87
88 return 0;
89 }
90 ```
91
92 ### 2. Chat Room Server
93
94 ```c
95 void Chat_Handler(Seobeo_WebSocket_Server_Connection *p_conn,
96 Seobeo_WebSocket_Message *p_msg, void *p_user_data)
97 {
98 if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
99 {
100 char message[2048];
101 snprintf(message, sizeof(message), "[%s]: %.*s",
102 p_conn->client_id, (int)p_msg->length, (char*)p_msg->data);
103
104 printf("Broadcasting: %s\n", message);
105 Seobeo_WebSocket_Server_Broadcast_Text(message);
106 }
107 }
108
109 int main()
110 {
111 Seobeo_WebSocket_Server_Init();
112 Seobeo_WebSocket_Server_Register("/chat", Chat_Handler, NULL);
113
114 printf("Chat server started on ws://localhost:8080/chat\n");
115 Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0);
116
117 return 0;
118 }
119 ```
120
121 ### 3. Binary Data Broadcasting
122
123 ```c
124 void Binary_Handler(Seobeo_WebSocket_Server_Connection *p_conn,
125 Seobeo_WebSocket_Message *p_msg, void *p_user_data)
126 {
127 if (p_msg->opcode == SEOBEO_WS_OPCODE_BINARY)
128 {
129 printf("Received %zu bytes, broadcasting...\n", p_msg->length);
130 Seobeo_WebSocket_Server_Broadcast_Binary(p_msg->data, p_msg->length);
131 }
132 }
133
134 int main()
135 {
136 Seobeo_WebSocket_Server_Init();
137 Seobeo_WebSocket_Server_Register("/binary", Binary_Handler, NULL);
138
139 Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0);
140 return 0;
141 }
142 ```
143
144 ### 4. Multiple Endpoints
145
146 ```c
147 void Echo_Handler(Seobeo_WebSocket_Server_Connection *p_conn,
148 Seobeo_WebSocket_Message *p_msg, void *p_user_data)
149 {
150 if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
151 Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data);
152 }
153
154 void Chat_Handler(Seobeo_WebSocket_Server_Connection *p_conn,
155 Seobeo_WebSocket_Message *p_msg, void *p_user_data)
156 {
157 if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
158 {
159 char msg[2048];
160 snprintf(msg, sizeof(msg), "[%s]: %.*s",
161 p_conn->client_id, (int)p_msg->length, (char*)p_msg->data);
162 Seobeo_WebSocket_Server_Broadcast_Text(msg);
163 }
164 }
165
166 int main()
167 {
168 Seobeo_WebSocket_Server_Init();
169
170 // Register multiple WebSocket endpoints
171 Seobeo_WebSocket_Server_Register("/echo", Echo_Handler, NULL);
172 Seobeo_WebSocket_Server_Register("/chat", Chat_Handler, NULL);
173
174 printf("Server started with:\n");
175 printf(" ws://localhost:8080/echo - Echo server\n");
176 printf(" ws://localhost:8080/chat - Chat room\n");
177
178 Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0);
179 return 0;
180 }
181 ```
182
183 ### 5. Custom User Data
184
185 ```c
186 typedef struct {
187 int message_count;
188 char name[64];
189 } ChatRoomData;
190
191 void Chat_Handler_With_Data(Seobeo_WebSocket_Server_Connection *p_conn,
192 Seobeo_WebSocket_Message *p_msg, void *p_user_data)
193 {
194 ChatRoomData *p_data = (ChatRoomData*)p_user_data;
195
196 if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
197 {
198 p_data->message_count++;
199
200 char message[2048];
201 snprintf(message, sizeof(message), "[%s #%d]: %.*s",
202 p_data->name, p_data->message_count,
203 (int)p_msg->length, (char*)p_msg->data);
204
205 Seobeo_WebSocket_Server_Broadcast_Text(message);
206 }
207 }
208
209 int main()
210 {
211 ChatRoomData room_data = {0};
212 strcpy(room_data.name, "Main Room");
213
214 Seobeo_WebSocket_Server_Init();
215 Seobeo_WebSocket_Server_Register("/chat", Chat_Handler_With_Data, &room_data);
216
217 Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0);
218 return 0;
219 }
220 ```
221
222 ### 6. Mixed HTTP and WebSocket Server
223
224 ```c
225 // HTTP route handler
226 Seobeo_Request_Entry* Get_Status(Seobeo_Request_Entry *req, Dowa_Arena *arena)
227 {
228 Seobeo_Request_Entry *resp = NULL;
229 Dowa_HashMap_Push_Arena(resp, "status", "200", arena);
230 Dowa_HashMap_Push_Arena(resp, "content-type", "application/json", arena);
231 Dowa_HashMap_Push_Arena(resp, "body", "{\"status\": \"online\"}", arena);
232 return resp;
233 }
234
235 // WebSocket handler
236 void WS_Handler(Seobeo_WebSocket_Server_Connection *p_conn,
237 Seobeo_WebSocket_Message *p_msg, void *p_user_data)
238 {
239 if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT)
240 Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data);
241 }
242
243 int main()
244 {
245 // Initialize both HTTP and WebSocket routing
246 Seobeo_Router_Init();
247 Seobeo_WebSocket_Server_Init();
248
249 // Register HTTP routes
250 Seobeo_Router_Register("GET", "/api/status", Get_Status);
251
252 // Register WebSocket routes
253 Seobeo_WebSocket_Server_Register("/ws", WS_Handler, NULL);
254
255 printf("Server started:\n");
256 printf(" HTTP: http://localhost:8080/api/status\n");
257 printf(" WebSocket: ws://localhost:8080/ws\n");
258
259 Seobeo_Web_Server_Start("./public", "8080", SEOBEO_MODE_FORK, 0);
260 return 0;
261 }
262 ```
263
264 ## Building
265
266 ### Build the server example:
267 ```bash
268 bazel build //seobeo:websocket_server_example
269 ```
270
271 ### Run the server:
272 ```bash
273 bazel-bin/seobeo/websocket_server_example
274 ```
275
276 ### Test with a client:
277 You can test the server using the WebSocket client API or any WebSocket client tool:
278 ```bash
279 # Using websocat (install: cargo install websocat)
280 websocat ws://localhost:8080/echo
281
282 # Using wscat (install: npm install -g wscat)
283 wscat -c ws://localhost:8080/chat
284 ```
285
286 ## Connection Structure
287
288 ```c
289 struct Seobeo_WebSocket_Server_Connection_Struct {
290 Seobeo_Handle *p_handle; // Underlying socket handle
291 char *client_id; // Unique client identifier
292 boolean is_active; // Connection status
293
294 // Fragment handling (internal)
295 uint8 *fragment_buffer;
296 size_t fragment_length;
297 size_t fragment_capacity;
298 Seobeo_WebSocket_Opcode fragment_opcode;
299
300 Seobeo_WebSocket_Server_Connection *next; // Linked list
301 };
302 ```
303
304 ## Protocol Details
305
306 The server implementation follows RFC 6455:
307
308 1. **Handshake**: Responds to HTTP Upgrade requests with proper Sec-WebSocket-Accept key
309 2. **Frame Format**: Server sends unmasked frames (RFC requirement)
310 3. **Frame Receiving**: Server receives and unmasks client frames
311 4. **Fragmentation**: Handles fragmented messages automatically
312 5. **Control Frames**: Proper handling of ping, pong, and close frames
313 6. **Broadcast**: Efficiently sends to all active connections
314
315 ## Key Differences from Client
316
317 | Feature | Client | Server |
318 |---------|--------|--------|
319 | Frame Masking | Masks outgoing frames | Does NOT mask outgoing frames |
320 | Connection | Initiates connection | Accepts connections |
321 | Upgrade | Sends upgrade request | Responds to upgrade request |
322 | Multiple Connections | Single connection | Manages multiple connections |
323 | Broadcast | N/A | Can broadcast to all clients |
324
325 ## Coding Standards
326
327 The implementation follows your specified coding standards:
328 - Naming: `Seobeo_WebSocket_Server_Init`, `Seobeo_WebSocket_Server_Send_Text`
329 - Two spaces for indentation
330 - New line before `{` unless it's a struct
331 - Single statement: no need for `{}`
332
333 ## Integration with Existing Server
334
335 The WebSocket server integrates seamlessly:
336
337 1. **Automatic Detection**: The HTTP server automatically checks for WebSocket upgrade requests
338 2. **No Conflicts**: WebSocket and HTTP routes coexist peacefully
339 3. **Same Port**: WebSocket and HTTP share the same server port
340 4. **Unified Server**: Use `Seobeo_Web_Server_Start()` for everything
341
342 ## Testing the Server
343
344 ### JavaScript Client (Browser):
345 ```javascript
346 const ws = new WebSocket('ws://localhost:8080/echo');
347
348 ws.onopen = () => {
349 console.log('Connected!');
350 ws.send('Hello, Server!');
351 };
352
353 ws.onmessage = (event) => {
354 console.log('Received:', event.data);
355 };
356 ```
357
358 ### Python Client:
359 ```python
360 import websocket
361
362 ws = websocket.create_connection("ws://localhost:8080/chat")
363 ws.send("Hello from Python!")
364 print(ws.recv())
365 ws.close()
366 ```
367
368 ## Performance Considerations
369
370 1. **Fork Mode**: Each connection runs in a separate process (SEOBEO_MODE_FORK)
371 2. **Edge Mode**: Multi-threaded connections (SEOBEO_MODE_EDGE)
372 3. **Broadcast**: Iterates through all connections (O(n) complexity)
373 4. **Fragmentation**: Large messages are automatically fragmented (1MB chunks)
374
375 ## Complete Feature Comparison
376
377 | Feature | Implemented |
378 |---------|-------------|
379 | ✅ WebSocket upgrade handshake | Yes |
380 | ✅ Text messages | Yes |
381 | ✅ Binary messages | Yes |
382 | ✅ Message fragmentation | Yes |
383 | ✅ Ping/Pong | Yes |
384 | ✅ Close handshake | Yes |
385 | ✅ Multiple endpoints | Yes |
386 | ✅ Broadcast | Yes |
387 | ✅ Connection tracking | Yes |
388 | ✅ Integration with HTTP server | Yes |
389 | ✅ Custom user data per handler | Yes |
390
391 The Seobeo WebSocket Server provides a complete, production-ready WebSocket implementation that works seamlessly with the existing HTTP server!