std.net.tcp_client / std.net.tcp_server
std.net.tcp_client / std.net.tcp_server
TCP in Scrii is message-based (not stream-based). You send whole messages with send and receive them whole in on_receive. Both client and server share the same event-driven model: install callbacks, start, sleep to keep the script alive.
Client
var c = std.net.tcp_client()
c.connect("127.0.0.1", 8999)
print(c.is_connected()) # true
c.on_receive(fn(data) {
print("got:", data) # fires when the server sends a line
})
c.send("hello")
std.async.sleep(500) # keep the script alive: without this the script exits and on_receive never fires
c.close()
| Method | Description |
|---|---|
connect(host, port[, {tls, verify}]) |
Connect to host:port; {tls: true} enables TLS, {verify: false} skips cert check (self-signed). Throws on failure |
is_connected() |
true while the socket is open |
send(data) |
Send a message (string) |
on_receive(fn(data)) |
Callback per incoming message |
on_disconnect(fn()) |
Fires exactly once when the connection is lost (remote close, error, or local close()); use last_error() for the cause |
set_keep_alive(false | {enabled[, idle_ms, interval_ms, count]}) |
TCP keepalive probes on idle connections; applies immediately and to future connect() calls |
last_error() |
Most recent background error (recv failure or callback exception) |
close() |
Disconnect |
The client has no on_connect — connect itself succeeds or throws. Reconnect by creating a new tcp_client().
Server — full echo server
var s = std.net.tcp_server()
s.on_connect(fn(id) {
print("client connected, id", id) # numeric session id
})
s.on_receive(fn(id, data) {
print("from", id, ":", data)
s.send(id, "echo: " + data) # reply to that client only
})
s.on_disconnect(fn(id) {
print("client", id, "disconnected")
})
s.listen(8999, "127.0.0.1") # port [, host] — host defaults to 0.0.0.0
print("listening on", s.port()) # actual bound port (useful when port is 0)
s.broadcast("hello everyone") # to all connected clients
std.async.sleep(5000) # keep serving: exiting the script would stop the server with it
s.stop() # stop accepting, close all
Pair it with the client above in another process — the client sends "ping", the server replies "echo: ping".
| Method | Description |
|---|---|
listen(port[, host[, {cert, key}]]) |
Start accepting; {cert, key} from PEM files makes it serve TLS. Callbacks fire only after this |
port() |
Actual bound port (handy when you passed 0) |
on_connect(fn(id)) |
Per new client (id is session) |
on_receive(fn(id, data)) |
Per message from a client |
on_disconnect(fn(id)) |
When a client leaves |
send(id, data) |
Send to one client → true on success |
broadcast(data) |
Send to every client → count queued |
disconnect(id) |
Force-close one client |
set_keep_alive(false | {enabled[, idle_ms, interval_ms, count]}) |
TCP keepalive probes on idle connections; applies to live peers and future accept() calls |
is_running() / stop() |
Query / halt server |
last_error() |
Most recent background error (accept/TLS failure or callback exception) |
Lifecycle and errors
- Callbacks run on background fibers — the main script must sleep/await or it exits and callbacks are abandoned (see Concurrency).
- TLS requires an OpenSSL build; without it,
{tls: true}/{cert, key}throwUNSUPPORTED(see Overview). - Background failures with no caller (TLS handshake, recv failures, callback exceptions) are recorded per object and read via
last_error()— also echoed to stderr. Connection-time failures (unresolvable host, refused port) throw fromconnect/listeninstead (see Errors). - Pass
0tolisten()to let the OS pick a free port, then read it back
withport()and share it (via file,print, etc.).
See also
- UDP — connectionless alternative
- Overview — the event model and TLS note
- Concurrency —
sleepthat keeps the server alive