# net — TCP client/server builtins Blocking, cross-platform TCP over the runtime's Io engine. ## Listening ```rinne @import = .{ net, std }; const l = net.tcp_listen(0); // port 0 = ephemeral; pick with l.port() std.print("listening on {}\n", .{l.port()}); ``` | Listener method | Effect | |-----------------|-------------------------------------------| | `l.port()` | bound port (resolves ephemeral port 0) | | `l.accept()` | block until a client arrives → stream | | `l.close()` | stop listening | ## Connecting ```rinne @import = .{ net, std }; const c = net.tcp_connect("127.0.0.1", 8080); ``` ## Streams | Stream method | Effect | |---------------------|-----------------------------------------------------------| | `s.read(max)` | up to `max` bytes as a string; **returns early at EOF**, otherwise waits for bytes | | `s.write(data)` | send a string (flushed before returning); returns length | | `s.shutdown(how)` | half-close; `how` = `"send"`, `"recv"`, `"both"` (default `"send"`) | | `s.close()` | close the socket | > **Message framing:** on blocking platforms `read(max)` cannot know where > your message ends. Half-close the sender (`c.shutdown()`) after writing a > complete message — the peer's `read` then returns immediately at EOF while > the reverse direction stays open for the reply. Errors surface as runtime errors: cannot listen / cannot resolve host / cannot connect / accept failed / read or write failed. ## Runnable example (both roles in one script) ```rinne @import = .{ net, std }; pub fn main() int { const l = net.tcp_listen(0); const p = l.port(); std.print("listening on 127.0.0.1:{}\n", .{p}); const c = net.tcp_connect("127.0.0.1", p); c.write("ping"); c.shutdown(); const s = l.accept(); const got = s.read(64); std.print("server got: {}\n", .{got}); s.write("pong"); s.shutdown(); const back = c.read(64); std.print("client got: {}\n", .{back}); c.close(); s.close(); l.close(); return 0; } ``` ## More examples See `examples/net_demo.rg` — dual-role TCP loopback echo with half-close framing.