comparison mrjunejune/src/blog/websocket-demystified/index.md @ 132:7a63e41a21fb

[Seobeo] Added debug targets.
author June Park <parkjune1995@gmail.com>
date Fri, 09 Jan 2026 08:23:54 -0800
parents b230a743a01e
children 902e29c38d66
comparison
equal deleted inserted replaced
131:b230a743a01e 132:7a63e41a21fb
2 2
3 WebSockets have been around for more than 10 years now—the [RFC 6455](https://www.rfc-editor.org/rfc/rfc6455) was dropped way back in 2011. This was inevitable. As apps got more complex, people wanted real bidirectional communication without resorting to hacky solutions like raw TCP connections with custom keys or the constant overhead of short/long polling. 3 WebSockets have been around for more than 10 years now—the [RFC 6455](https://www.rfc-editor.org/rfc/rfc6455) was dropped way back in 2011. This was inevitable. As apps got more complex, people wanted real bidirectional communication without resorting to hacky solutions like raw TCP connections with custom keys or the constant overhead of short/long polling.
4 4
5 Today, it’s the standard for everything from chat apps to LLM interfaces, where the model streams bytes back to you one token at a time as it predicts the next word. 5 Today, it’s the standard for everything from chat apps to LLM interfaces, where the model streams bytes back to you one token at a time as it predicts the next word.
6 6
7 Most developers just grab a library like [ws](https://github.com/websockets/ws) for Node.js or [websockets](https://websockets.readthedocs.io/) for Python and call it a day. But many don’t realize the underlying mechanism is actually pretty simple to implement yourself in a day or so. Let's look at how to build it from scratch. 7 Most developers just grab a library like [ws](https://github.com/websockets/ws) for Node.js or [websockets](https://websockets.readthedocs.io/) for Python and call it a day. But many don’t realize the underlying mechanism is actually pretty simple to implement yourself in a day or so. Also they misunderstand what websocket actually do. Let's look at how to build it from scratch and debunk myths.
8
9 ### The "65,535" Myth
10
11 Before we write a single line of code, Let's talk about common myth. You’ll often hear developers say, *"A server can only handle 65,535 WebSocket connections because there are only 65,535 ports."*
12
13 If this were true, Discord or Slack would need millions of separate IP addresses just to function. The confusion comes from the 16-bit size of the TCP port field, but a connection isn't defined by a port alone. You will see in this blog.
8 14
9 --- 15 ---
10 16
11 ## Requirements 17 ## Requirements
12 18
13 * Ability to type 19 * Ability to type
14 * Half a brain 20 * Half a brain to real mechanics, not the surface-level myths.
15 * A computer 21 * A computer
16 22
17 --- 23 ---
18 24
19 ## The Lifecycle 25 ## The Lifecycle
29 35
30 ## Opening Handshakes 36 ## Opening Handshakes
31 37
32 To start the upgrade from HTTP to WebSocket, the client sends a standard GET request but with some very specific headers. 38 To start the upgrade from HTTP to WebSocket, the client sends a standard GET request but with some very specific headers.
33 39
34 <div class="center"> <img src="/public/white-noise-grass.png" /> </div> 40 <div class="center"> <img src="/public/web-socket-header.webp" /> </div>
41
35 42
36 I’m assuming you know how HTTP works. If not, you can open a developer tool by right clicking on your browser and seeing into network tab and refershign the page. The only interesting values here is the `Sec-WebSocket-Key`. This key is usually a 16-byte random value encoded in **Base64**. 43 I’m assuming you know how HTTP works. If not, you can open a developer tool by right clicking on your browser and seeing into network tab and refershign the page. The only interesting values here is the `Sec-WebSocket-Key`. This key is usually a 16-byte random value encoded in **Base64**.
37 44
38 **Note:** It’s not for security—it’s to prevent intermediate caches from accidentally serving a cached WebSocket response to a different client. 45 **Note:** It’s not for security—it’s to prevent intermediate caches from accidentally serving a cached WebSocket response to a different client.
39 46
122 ```c 129 ```c
123 // Transitioning the state from HTTP to WebSocket 130 // Transitioning the state from HTTP to WebSocket
124 Seobeo_WebSocket_Server_Connection *p_conn = malloc(sizeof(Seobeo_WebSocket_Server_Connection)); 131 Seobeo_WebSocket_Server_Connection *p_conn = malloc(sizeof(Seobeo_WebSocket_Server_Connection));
125 memset(p_conn, 0, sizeof(Seobeo_WebSocket_Server_Connection)); 132 memset(p_conn, 0, sizeof(Seobeo_WebSocket_Server_Connection));
126 133
127 p_conn->p_handle = p_handle; 134 p_conn->p_handle = p_handle; // file descriptor
128 p_conn->is_active = TRUE; 135 p_conn->is_active = TRUE;
129 p_conn->fragment_capacity = 4096; 136 p_conn->fragment_capacity = 4096;
130 p_conn->fragment_buffer = malloc(p_conn->fragment_capacity); 137 p_conn->fragment_buffer = malloc(p_conn->fragment_capacity);
131 138
132 ``` 139 ```
140
141 ### Wait, what is the p_handle or file descriptor here??
142
143 The File Descriptor (FD) is the internal ID badge your server assigns to a connection. The OS identifies a unique connection via a 4-tuple; Source IP, Source Port, Destination IP, Destination Port. You can think of the OS as a giant hashmap that links these 4-tuples to an integer (the FD).
144
145 So the limits are from the number of FD and RAM capactiy. You can check your system's FD limit with:
146
147 ```bash
148 ulimit -n
149 ```
150
151 Now, we have debunked this myth. Let's see how the protocol actually works.
133 152
134 --- 153 ---
135 154
136 ## Frame-Based Protocols 155 ## Frame-Based Protocols
137 156