|
| 1 | +\page networking BASIC Networking |
| 2 | + |
| 3 | +[TOC] |
| 4 | + |
| 5 | +### Introduction to Sockets |
| 6 | + |
| 7 | +Retro Rocket BASIC is not limited to files, graphics, and local input/output. |
| 8 | +It also has direct **network and Internet access**, built into the language itself. |
| 9 | +This is provided through **sockets**. |
| 10 | + |
| 11 | +A socket is a numbered channel that lets your program send and receive data across the network. With sockets you can: |
| 12 | + |
| 13 | +* **Build clients** that connect to remote services such as web servers, APIs, or other Retro Rocket programs. |
| 14 | +* **Build servers** that listen for incoming connections from other machines, whether on your local network or the wider Internet. |
| 15 | +* **Exchange data directly** between two programs on the same computer without using files. |
| 16 | + |
| 17 | +Sockets are deliberately designed to be simple in Retro Rocket BASIC. You do not need to know about retries, buffers, or low-level networking details. A few straightforward keywords are enough to open a connection, send and receive data, and close it again. |
| 18 | + |
| 19 | +This section of the manual introduces sockets, shows how to create both clients and servers, and explains the two kinds of socket Retro Rocket provides: |
| 20 | + |
| 21 | +* **TCP sockets** for reliable, ordered conversations. |
| 22 | +* **UDP sockets** for quick, lightweight messages. |
| 23 | + |
| 24 | +Once you understand these, you can write networked applications such as web servers, chat clients, multiplayer games, and telemetry systems - all in BASIC, with the same clarity and brevity as printing text to the screen. |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +### Understanding Sockets (Phone Calls vs Parcels) |
| 29 | + |
| 30 | +Networking in Retro Rocket BASIC uses **sockets**: simple handles (just numbers) that let programs talk over the network. There are two flavours with very different “feel”: |
| 31 | + |
| 32 | +* **TCP** - like a **phone call**: a live conversation with guaranteed order and delivery. |
| 33 | +* **UDP** - like posting a **parcel**: each item is sent on its own; most arrive, some may not. |
| 34 | + |
| 35 | +You don’t need to learn object systems, callbacks, or frameworks. The flow is linear: **connect/listen → read/write → flush (if needed) → close**. |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +#### TCP - Like a Phone Call (reliable conversation) |
| 40 | + |
| 41 | +TCP aims to feel like you’ve got a dedicated line once connected. |
| 42 | + |
| 43 | +* \ref CONNECT "CONNECT" - dial the other side. Their phone “rings”. |
| 44 | +* \ref SOCKLISTEN "SOCKLISTEN" - keep your phone on, ready to receive calls on a number (port). |
| 45 | +* \ref SOCKACCEPT "SOCKACCEPT" - swipe to answer when someone calls. Each accepted call gets a **new** socket handle (a new line). |
| 46 | +* \ref SOCKWRITE "SOCKWRITE" - speak; your words are queued exactly as you said them. |
| 47 | +* \ref SOCKFLUSH "SOCKFLUSH" - pause for the “**uh-huh**”: make sure what you said is pushed out and acknowledged before carrying on. |
| 48 | +* \ref SOCKREAD "SOCKREAD" - listen; you receive complete values (string / integer / real) in the right order. |
| 49 | +* \ref SOCKCLOSE "SOCKCLOSE" - hang up; the line is gone. |
| 50 | + |
| 51 | +**What you get with TCP** |
| 52 | + |
| 53 | +* **No missing words**: bytes aren’t lost. |
| 54 | +* **Correct order**: bytes arrive exactly as sent. |
| 55 | +* **Simple flow**: write → flush → read → close; no retries, no partial-send faff. |
| 56 | + |
| 57 | +**Use TCP for** web pages, chat, control channels, file transfer-anything where every byte matters. |
| 58 | + |
| 59 | +--- |
| 60 | + |
| 61 | +#### UDP - Like Sending a Parcel (quick, independent messages) |
| 62 | + |
| 63 | +UDP is fire-and-forget. Each message is its own parcel. |
| 64 | + |
| 65 | +* \ref UDPBIND "UDPBIND" - write your return address on the box and open your doorstep (port). Both sides should **bind** so they have a clear return address and a place to receive. |
| 66 | +* \ref UDPWRITE "UDPWRITE" - pack a parcel and drop it at the post office. It **leaves immediately**. There’s no built-in receipt or guarantee. |
| 67 | +* \ref UDPREAD "UDPREAD$" - open the door and pick up the **next** parcel on your doorstep. |
| 68 | +* \ref UDPLASTIP "UDPLASTIP$" / \ref UDPLASTSOURCEPORT "UDPLASTSOURCEPORT" - read the sender label (who posted this parcel and from which port) **for the parcel you just picked up**. |
| 69 | + |
| 70 | +**What you get with UDP** |
| 71 | + |
| 72 | +* **Speed & simplicity**: no call setup, no flush. |
| 73 | +* **Independence**: each message stands alone; send one or many. |
| 74 | +* **No guarantees**: a parcel can be delayed, arrive out of order, or never turn up. |
| 75 | + |
| 76 | +**Use UDP for** quick updates, game ticks, “is-alive” beacons, mouse/keyboard telemetry-cases where losing the odd packet doesn’t hurt. |
| 77 | + |
| 78 | +--- |
| 79 | + |
| 80 | +### Side-by-side: Phone Call vs Parcel |
| 81 | + |
| 82 | +| Aspect | **TCP (Phone Call)** | **UDP (Parcel Post)** | |
| 83 | +| ------------- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | |
| 84 | +| How you start | `CONNECT` to call; server `SOCKLISTEN` + `SOCKACCEPT` to answer. | Both sides `UDPBIND` a port (their doorstep). No call setup. | |
| 85 | +| Identity | Each accepted TCP socket is a known line between two ends. | Each parcel carries its own label; use `UDPLASTIP$` / `UDPLASTSOURCEPORT` after `UDPREAD$`. | |
| 86 | +| Sending | `SOCKWRITE` queues words; `SOCKFLUSH` waits for “uh-huh”. | `UDPSEND`/`UDPWRITE` posts a parcel immediately. No flush. | |
| 87 | +| Receiving | `SOCKREAD` waits for complete data; order guaranteed. | `UDPREAD$` pops **one** parcel from the doorstep queue; order not guaranteed. | |
| 88 | +| Delivery | Guaranteed and ordered. | Best-effort; may be delayed, re-ordered, or lost. | |
| 89 | +| Ending | `SOCKCLOSE` hangs up the line. | `SOCKCLOSE`/`UDPUNBIND` stops using that doorstep. | |
| 90 | + |
| 91 | +--- |
| 92 | + |
| 93 | +### UDP “Doorstep Queue” (how incoming messages are stored) |
| 94 | + |
| 95 | +When your program `UDPBIND`s a port, Retro Rocket keeps an **in-memory queue** of incoming UDP packets for that port-think **parcels on your doorstep**: |
| 96 | + |
| 97 | +* Every new packet is placed at the **back** of the queue for that port. |
| 98 | +* Each call to \ref UDPREAD "UDPREAD$ pops **one** packet from the **front** of the queue and returns its contents as a string. |
| 99 | +* After a successful \ref UDPREAD "UDPREAD$ the “label” values for that packet are available via: |
| 100 | + |
| 101 | + * \ref UDPLASTIP "UDPLASTIP$" - sender’s address (the return address). |
| 102 | + * \ref UDPLASTSOURCEPORT "UDPLASTSOURCEPORT" - sender’s source port (their posting office counter). |
| 103 | + These **do not take parameters**: they always refer to the **most recently read** packet. |
| 104 | + |
| 105 | +This model is simple, predictable, and maps perfectly to the “parcel on the doorstep” intuition. |
| 106 | + |
| 107 | +--- |
| 108 | + |
| 109 | +### Worked UDP Example - Mouse Telemetry |
| 110 | + |
| 111 | +Below is your exact module, which binds a per-process port and polls a local mouse server. It showcases `UDPBIND`, `UDPWRITE`, `UDPREAD$`, and consuming one packet at a time: |
| 112 | + |
| 113 | +```basic |
| 114 | +DEF PROCmouse |
| 115 | + __MOUSE_X = GRAPHICS_WIDTH / 2 |
| 116 | + __MOUSE_Y = GRAPHICS_HEIGHT / 2 |
| 117 | + __MOUSE_LMB = FALSE |
| 118 | + __MOUSE_RMB = FALSE |
| 119 | + __MOUSE_MMB = FALSE |
| 120 | + UDPBIND "127.0.0.1", 14502 + PID |
| 121 | +ENDPROC |
| 122 | +
|
| 123 | +DEF PROCmouse_done |
| 124 | + UDPUNBIND "127.0.0.1", 14502 + PID |
| 125 | +ENDPROC |
| 126 | +
|
| 127 | +DEF PROCfetch_mouse |
| 128 | + UDPWRITE "127.0.0.1", 14502 + PID, 14501, "GET" |
| 129 | + PACKET$ = UDPREAD$(14502 + PID) |
| 130 | + IF PACKET$ <> "" THEN |
| 131 | + X$ = TOKENIZE$(PACKET$, " ") |
| 132 | + Y$ = TOKENIZE$(PACKET$, " ") |
| 133 | + M$ = TOKENIZE$(PACKET$, " ") |
| 134 | + __MOUSE_X = VAL(X$) |
| 135 | + __MOUSE_Y = VAL(Y$) |
| 136 | + __MOUSE_BUTTONS = VAL(M$) |
| 137 | + __MOUSE_LMB = BITAND(__MOUSE_BUTTONS, 1) |
| 138 | + __MOUSE_RMB = BITSHR(BITAND(__MOUSE_BUTTONS, 2), 1) |
| 139 | + __MOUSE_MMB = BITSHR(BITAND(__MOUSE_BUTTONS, 4), 2) |
| 140 | + ENDIF |
| 141 | +ENDPROC |
| 142 | +
|
| 143 | +DEF FNmouse_x |
| 144 | +=__MOUSE_X |
| 145 | +
|
| 146 | +DEF FNmouse_y |
| 147 | +=__MOUSE_Y |
| 148 | +
|
| 149 | +DEF FNmouse_lmb |
| 150 | +=__MOUSE_LMB |
| 151 | +
|
| 152 | +DEF FNmouse_rmb |
| 153 | +=__MOUSE_RMB |
| 154 | +
|
| 155 | +DEF FNmouse_mmb |
| 156 | +=__MOUSE_MMB |
| 157 | +``` |
| 158 | + |
| 159 | +**What’s happening here (in parcel terms):** |
| 160 | + |
| 161 | +* `UDPBIND "127.0.0.1", 14502 + PID` opens **your doorstep** (unique port per process). |
| 162 | +* `UDPWRITE "127.0.0.1", 14502 + PID, 14501, "GET"` posts a **parcel** to the mouse server’s port **14501**, marking your doorstep **14502+PID** as the return address. |
| 163 | +* `UDPREAD$(14502 + PID)` **picks up the next parcel** that arrived for you. If none is present, it returns `""` and you carry on. |
| 164 | +* The packet encodes `x y buttons` separated by spaces; you slice those out and update state. |
| 165 | +* `UDPUNBIND` closes the doorstep when you’re done. |
| 166 | + |
| 167 | +Because each UDP packet is independent, you can lose one with negligible impact-the next packet will replace it a tick later, keeping the mouse fluid. |
| 168 | + |
| 169 | +--- |
| 170 | + |
| 171 | +### Practical Tips (UDP) |
| 172 | + |
| 173 | +* **Bind both sides**: have a predictable return address and a consistent inbox. |
| 174 | +* **Keep messages small**: fit comfortably within your UDP payload limit to avoid IP fragmentation. |
| 175 | +* **Design for loss**: treat every packet as optional; never rely on “the last one must have arrived”. |
| 176 | +* **Use the labels**: read `UDPLASTIP$` / `UDPLASTSOURCEPORT` **immediately after** `UDPREAD$` if you plan to reply. |
| 177 | + |
| 178 | +--- |
| 179 | + |
| 180 | +Right - good catch. For new users, we need to introduce the idea from first principles, **without starting with “DNS”**. Here’s a plain-English version that leads into the concept and only then names it: |
| 181 | + |
| 182 | +--- |
| 183 | + |
| 184 | +### Names and Addresses |
| 185 | + |
| 186 | +Every computer on the Internet has a unique **address number**, called an **IP address**. It looks like this: |
| 187 | + |
| 188 | +``` |
| 189 | +93.184.216.34 |
| 190 | +``` |
| 191 | + |
| 192 | +These numbers are what sockets really use. But numbers are hard to remember. People prefer names, like: |
| 193 | + |
| 194 | +``` |
| 195 | +example.org |
| 196 | +``` |
| 197 | + |
| 198 | +There is a worldwide system that matches names to numbers, just like your phone’s contact list matches a friend’s name to their phone number. On the Internet this system is called the **Domain Name System**, usually shortened to **DNS**. |
| 199 | + |
| 200 | +* When you type a name, DNS looks up the matching number. |
| 201 | +* Once you have the number, you can connect your socket to it. |
| 202 | +* The result is stored in a local cache, so asking for the same name again is instant. |
| 203 | + |
| 204 | +--- |
| 205 | + |
| 206 | +### The DNS$ Function |
| 207 | + |
| 208 | +Retro Rocket BASIC makes this simple with a single function: |
| 209 | + |
| 210 | +```basic |
| 211 | +ip$ = DNS$("example.org") |
| 212 | +``` |
| 213 | + |
| 214 | +* Returns the IP address as a string, e.g. `"93.184.216.34"`. |
| 215 | +* Returns `""` if the name cannot be looked up. |
| 216 | +* Uses caching automatically; you don’t need to worry about retries or speed. |
| 217 | + |
| 218 | +--- |
| 219 | + |
| 220 | +### Quick Examples |
| 221 | + |
| 222 | +#### TCP Client |
| 223 | + |
| 224 | +```basic |
| 225 | +' Connect to a web server |
| 226 | +sock = CONNECT("93.184.216.34", 80) |
| 227 | +SOCKWRITE sock, "GET / HTTP/1.0" + CHR$(13) + CHR$(10) + CHR$(13) + CHR$(10) |
| 228 | +SOCKFLUSH sock |
| 229 | +
|
| 230 | +' Read the response line |
| 231 | +SOCKREAD sock, line$ |
| 232 | +PRINT line$ |
| 233 | +
|
| 234 | +SOCKCLOSE sock |
| 235 | +``` |
| 236 | + |
| 237 | +--- |
| 238 | + |
| 239 | +#### TCP Server |
| 240 | + |
| 241 | +```basic |
| 242 | +' Listen on port 8080 |
| 243 | +server = SOCKLISTEN("0.0.0.0", 8080, 5) |
| 244 | +PRINT "Server running on port 8080" |
| 245 | +
|
| 246 | +REPEAT |
| 247 | + client = SOCKACCEPT(server) |
| 248 | + IF client >= 0 THEN |
| 249 | + SOCKWRITE client, "Hello from Retro Rocket!" |
| 250 | + SOCKFLUSH client |
| 251 | + SOCKCLOSE client |
| 252 | + ENDIF |
| 253 | +UNTIL INKEY$ <> "" |
| 254 | +
|
| 255 | +SOCKCLOSE server |
| 256 | +``` |
| 257 | + |
| 258 | +--- |
| 259 | + |
| 260 | +#### UDP Example |
| 261 | + |
| 262 | +```basic |
| 263 | +' Bind to port 5001 |
| 264 | +udp = UDPBIND("0.0.0.0", 5001) |
| 265 | +
|
| 266 | +' Send a packet to localhost:5001 |
| 267 | +UDPSEND udp, "127.0.0.1", 5001, "Ping" |
| 268 | +
|
| 269 | +' Read the next packet from the queue |
| 270 | +msg$ = UDPREAD$(5001) |
| 271 | +IF msg$ <> "" THEN |
| 272 | + PRINT "Got packet: "; msg$ |
| 273 | + PRINT "From: "; UDPLASTIP$; " Port: "; UDPLASTSOURCEPORT |
| 274 | +ENDIF |
| 275 | +
|
| 276 | +SOCKCLOSE udp |
| 277 | +``` |
| 278 | + |
| 279 | +#### Connecting by Name |
| 280 | + |
| 281 | +```basic |
| 282 | +ip$ = DNS$("example.org") |
| 283 | +IF ip$ <> "" THEN |
| 284 | + sock = CONNECT(ip$, 80) |
| 285 | + SOCKWRITE sock, "GET / HTTP/1.0" + CHR$(13) + CHR$(10) + CHR$(13) + CHR$(10) |
| 286 | + SOCKFLUSH sock |
| 287 | + SOCKREAD sock, reply$ |
| 288 | + PRINT reply$ |
| 289 | + SOCKCLOSE sock |
| 290 | +ELSE |
| 291 | + PRINT "Could not look up that name" |
| 292 | +ENDIF |
| 293 | +``` |
| 294 | + |
| 295 | +--- |
| 296 | + |
| 297 | +### Socket Keywords |
| 298 | + |
| 299 | +* \ref CONNECT |
| 300 | +* \ref DNS "DNS$" |
| 301 | +* \ref SOCKLISTEN |
| 302 | +* \ref SOCKACCEPT |
| 303 | +* \ref SOCKWRITE |
| 304 | +* \ref SOCKFLUSH |
| 305 | +* \ref SOCKREAD |
| 306 | +* \ref SOCKCLOSE |
| 307 | +* \ref UDPBIND |
| 308 | +* \ref UDPSEND |
| 309 | +* \ref UDPWRITE |
| 310 | +* \ref UDPREAD "UDPREAD$"" |
| 311 | +* \ref UDPLASTIP "UDPLASTIP$" |
| 312 | +* \ref UDPLASTSOURCEPORT |
| 313 | +* \ref UDPUNBIND |
0 commit comments