kex docs Standard Library 0.4.0-alpha kex.run ↗

Net.Socket

module Net.Socket

Process-owned TCP byte streams and listeners. All blocking operations return typed NetError values; close operations are idempotent.

using Net
using Net.Socket

let listener = TCP.listen(TCP.Endpoint.loopback(Port.from(0).try)).try
let address = listener.localAddress.try
let client = TCP.connect(address).try
client.sendAll("ping".to(Binary).try).try
listener.close

module Net.Socket.TCP

type Plain

Marker for an unencrypted stream.

type TCPConnection

An opaque connected TCP stream.

type TCPListener

An opaque TCP listening socket.

record Endpoint

A host name or numeric address paired with a validated port.

Fields

host
String
port
Net.Port

record ConnectOptions

Connection deadlines and operating-system socket policy.

Buffer values of zero leave sizing to the operating system. noDelay? disables Nagle's algorithm, which is usually right for request/response traffic; bulk-transfer protocols may prefer fewer, larger packets.

Fields

connectTimeout
Duration optional
noDelay?
Bool optional
keepAlive?
Bool optional
sendBuffer
Integer optional
receiveBuffer
Integer optional

record ListenOptions

Listener queue and policy inherited by accepted connections.

backlog bounds connections waiting for accept. Buffer values of zero keep the platform defaults rather than requesting a particular byte size.

Fields

backlog
Integer optional
reuseAddress?
Bool optional
noDelay?
Bool optional
keepAlive?
Bool optional
sendBuffer
Integer optional
receiveBuffer
Integer optional

module Net.Socket.TCP.Endpoint

function host

Pairs a hostname or numeric address with a port.

Resolution happens when connecting, so this preserves name exactly as supplied rather than validating it as an IP.Address.

host(name, port) : String -> Net.Port -> Endpoint

Returns: Endpoint — the remote or listening endpoint

Examples

Connecting by hostname

TCP.Endpoint.host("cache.internal", Port.from(6379).try)

function any

Builds an IPv4 wildcard endpoint for listening on every local interface.

Be deliberate with this in development: unlike loopback, it may expose the service to other machines on the network.

any(port) : Net.Port -> Endpoint

Returns: Endpoint — an IPv4 wildcard listening endpoint

Examples

Exposing a production service on port 8080

TCP.Endpoint.any(Port.from(8080).try)

function loopback

Builds an IPv4 loopback endpoint reachable only from this machine.

Port zero lets the operating system choose a free port, which is useful for tests; ask localAddress which port was assigned after listening.

loopback(port) : Net.Port -> Endpoint

Returns: Endpoint — an IPv4 loopback endpoint

Examples

Starting an isolated test listener

TCP.Endpoint.loopback(Port.from(0).try)

function connect

Connects to a TCP endpoint with the backend's bounded connect deadline.

connect(endpoint) : Endpoint -> Result<TCPConnection, NetError>
connect(endpoint) : Endpoint -> ConnectOptions -> Result<TCPConnection, NetError>

Returns: Result<TCPConnection, NetError> — a stream or Connect/Timeout

Examples

Connecting to a line-oriented local service

let endpoint = TCP.Endpoint.host("127.0.0.1", Port.from(9000).try)
let connection = TCP.connect(endpoint).try

function listen

Binds and starts listening. Port zero selects an ephemeral local port.

listen(endpoint) : Endpoint -> Result<TCPListener, NetError>
listen(endpoint) : Endpoint -> ListenOptions -> Result<TCPListener, NetError>

Returns: Result<TCPListener, NetError> — a listener or Connect

Examples

Giving each integration test its own free port

let listener = TCP.listen(TCP.Endpoint.loopback(Port.from(0).try)).try
let port = listener.localAddress.try.port

function sendAll

Sends every byte, retrying partial operating-system writes internally.

On failure, NetError.progress records how many bytes were accepted before the error. Do not blindly retry the whole payload when progress is present.

sendAll(connection, data)
Examples

Sending one newline-delimited request

connection.sendAll("status\n".to(Binary).try).try

function receiveChunk

Receives up to limit bytes; EOF is reported as Closed.

A successful result is one available chunk, not necessarily a complete application message. Use receiveExactly, receiveUntil, or receiveLine when the protocol supplies a boundary.

receiveChunk(connection, limit)
Examples

Reading up to 16 KiB from a streaming response

let chunk = connection.receiveChunk(16 * 1024).try

function receiveExactly

Receives exactly count bytes or returns a typed EOF/timeout failure.

Useful after a protocol header has declared the payload length.

receiveExactly(connection, count)
Examples

Reading a four-byte frame header

let header = connection.receiveExactly(4).try

function receiveUntil

Receives through the first delimiter without exceeding limit bytes.

The delimiter is included in the returned bytes. An empty delimiter is a Parse error; reaching the bound first is a Limit error.

receiveUntil(connection, delimiter, limit)
Examples

connection.receiveUntil("\r\n\r\n".to(Binary).try, 65536).try

function receiveLine

Receives through a newline without exceeding limit bytes.

The newline remains in the returned binary. Decode and trim only after a complete bounded line has been received.

receiveLine(connection, limit)
Examples

Reading a response line with a defensive 8 KiB limit

let line = connection.receiveLine(8192).try.to(String).try.trim

function shutdownWrite

Half-closes the write side while leaving reads available.

shutdownWrite(connection)

function accept

Waits for and returns the next connection accepted by the listener.

A timeout applies to this wait only; it does not become a read timeout on the returned connection.

accept(listener)
Examples

Accepting one client in a small test server

let client = listener.accept(5.seconds).try

function close

Idempotently closes a connected stream.

close(connection)

function closed?

closed?(connection)

Returns: Bool — whether the listener owner has stopped

function localAddress

Returns the bound local endpoint, including an ephemeral assigned port.

localAddress(connection)

function peerAddress

Returns the remote endpoint of a connected stream.

peerAddress(connection)
Examples

Recording the peer in an access log

let peer = connection.peerAddress.try
IO.printLine("accepted ${peer.host}:${peer.port.string}")

module Net.Socket.UDP

type Socket

Connectionless datagrams. A receive limit rejects an oversized datagram instead of returning a silently truncated payload.

let socket = UDP.bind(UDP.Endpoint.loopback(Port.from(0).try)).try
let address = socket.localAddress.try
socket.sendTo(address, "hello".to(Binary).try).try
let packet = socket.receiveFrom(1024).try
socket.close

An opaque bound datagram socket.

record Endpoint

A datagram address paired with a validated port.

Fields

host
String
port
Net.Port

record Datagram

A received datagram and its source endpoint.

Reply to source rather than the socket's local address: UDP has no connection that remembers which peer sent the packet.

Fields

source
Endpoint
data
Binary

record BindOptions

Curated socket policy. Broadcast is opt-in. The receive timeout applies to each receiveFrom call; multicast TTL is bounded to the IP hop-limit range.

Fields

broadcast?
Bool optional
multicastTtl
Integer optional
multicastLoopback?
Bool optional
receiveTimeout
Duration optional

module Net.Socket.UDP.Endpoint

function host

Pairs a hostname or numeric address with a UDP port.

host(name, port) : String -> Net.Port -> Endpoint

Returns: Endpoint — an endpoint using name exactly as supplied

Examples

Addressing a local metrics collector

UDP.Endpoint.host("metrics.internal", Port.from(8125).try)

function any

Builds an IPv4 wildcard endpoint for receiving on every local interface.

any(port) : Net.Port -> Endpoint

Returns: Endpoint — an IPv4 wildcard endpoint

Examples

Receiving discovery packets on port 9999

UDP.Endpoint.any(Port.from(9999).try)

function loopback

Builds an IPv4 loopback endpoint reachable only from this machine.

loopback(port) : Net.Port -> Endpoint

Returns: Endpoint — an IPv4 loopback endpoint

Examples

Allocating a free UDP port for a test

UDP.Endpoint.loopback(Port.from(0).try)

function bind

Binds a datagram socket. Port zero selects an ephemeral local port.

bind(endpoint) : Endpoint -> Result<Socket, NetError>
bind(endpoint) : Endpoint -> BindOptions -> Result<Socket, NetError>
Examples

A local UDP echo test

let socket = UDP.bind(UDP.Endpoint.loopback(Port.from(0).try)).try
let endpoint = socket.localAddress.try

function sendTo

Sends one complete datagram and returns its byte count.

Datagram boundaries are preserved: one sendTo corresponds to one receiveFrom, unless the packet is lost by the network.

sendTo(socket, endpoint, data)
Examples

Sending a StatsD-style counter

socket.sendTo(collector, "orders:1|c".to(Binary).try).try

function receiveFrom

Receives one datagram no larger than limit bytes.

Oversized packets fail with Limit instead of being silently truncated, so a caller never mistakes a prefix for a complete message.

receiveFrom(socket, limit)
Examples

Receiving and replying to one packet

let packet = socket.receiveFrom(4096).try
socket.sendTo(packet.source, packet.data).try

function close

Idempotently closes the socket.

close(socket)

function closed?

closed?(socket)

Returns: Bool — whether the socket owner has stopped

function localAddress

Returns the bound endpoint, including an ephemeral assigned port.

localAddress(socket)

function joinMulticast

Joins an IPv4 multicast group on the selected local interface. The group must be multicast and the interface must be an IPv4 address.

joinMulticast(socket, group, interface)

function leaveMulticast

Leaves a membership previously joined with the same group and interface.

leaveMulticast(socket, group, interface)

module Net.Socket.Unix

type UnixConnection

Filesystem-domain streams for local IPC. The listener owns and removes only the socket path it successfully created.

let address = Unix.Address.path("/tmp/my-service.sock").try
let listener = Unix.listen(address).try
let client = Unix.connect(address).try
listener.close

An opaque connected filesystem-domain byte stream.

type UnixListener

An opaque filesystem-domain stream listener.

record Address

A validated absolute filesystem socket path.

Fields

path
String

record ConnectOptions

Connection and read deadlines for a local IPC client.

Fields

connectTimeout
Duration optional
receiveTimeout
Duration optional

record ListenOptions

Listener queue, stale-socket policy, and per-operation deadlines.

removeStale? removes only a filesystem socket, never a regular file or directory that happens to occupy the requested path.

Fields

backlog
Integer optional
removeStale?
Bool optional
acceptTimeout
Duration optional
receiveTimeout
Duration optional

module Net.Socket.Unix.Address

function path

Validates a nonempty absolute Unix-domain socket path.

Relative paths are rejected so ownership and cleanup always refer to one unambiguous filesystem entry.

path(value) : String -> Result<Address, NetError>

Returns: Result<Address, NetError> — the address, or Parse

Examples

Addressing a per-user background service

Unix.Address.path("/tmp/my-app.sock").try

function connect

Connects to a filesystem-domain listener.

Unix sockets avoid opening a network port and are a good fit for two processes on the same machine, such as a CLI and its background daemon.

connect(address) : Address -> Result<UnixConnection, NetError>
connect(address) : Address -> ConnectOptions -> Result<UnixConnection, NetError>
Examples
let daemon = Unix.connect(Unix.Address.path("/tmp/my-app.sock").try).try

function listen

Binds a new path; an existing filesystem entry is never removed implicitly.

This conservative default protects regular files and also avoids taking over a socket that may still belong to a running service.

listen(address) : Address -> Result<UnixListener, NetError>
listen(address) : Address -> ListenOptions -> Result<UnixListener, NetError>

function sendAll

Sends every byte and returns the count.

sendAll(connection, data)

function receiveChunk

Receives one bounded chunk; EOF is Closed.

receiveChunk(connection, limit)

function receiveExactly

Receives exactly count bytes or returns a typed EOF/timeout failure.

receiveExactly(connection, count)

function receiveUntil

Receives through delimiter, including it, within an explicit bound.

receiveUntil(connection, delimiter, limit)
Examples

connection.receiveUntil("\n".to(Binary).try, 4096).try

function receiveLine

Receives through a newline without exceeding limit bytes.

receiveLine(connection, limit)

function shutdownWrite

Half-closes the write side while leaving reads available.

shutdownWrite(connection)

function accept

Waits for and returns the next stream connection.

accept(listener)

function close

Idempotently closes a stream.

close(connection)

function closed?

closed?(connection)

Returns: Bool — whether the listener owner has stopped

module Net.Socket.TLS

type TLSConnection

TLS client streams. Certificate and hostname verification are enabled by default; disabling verification must be an explicit configuration choice.

let endpoint = TCP.Endpoint.host("example.test", Port.from(443).try)
let tls = TLS.connect(endpoint, TLS.ClientConfig {
  serverName: "example.test"
}).try
tls.close

An opaque verified or explicitly unverified TLS byte stream.

record ClientConfig

Client handshake policy. TLS 1.2/1.3 are enabled; verification defaults on.

Fields

serverName
String
verify?
Bool optional
alpn
[String] optional

function connect

Opens a direct TLS connection with a bounded handshake deadline.

serverName drives both certificate hostname verification and SNI. Pass the DNS name from the URL, not an address it happened to resolve to.

connect(endpoint, config) : Net.Socket.TCP.Endpoint -> ClientConfig -> Result<TLSConnection, NetError>

Returns: Result<TLSConnection, NetError> — a TLS stream or typed failure

Examples

Opening a verified connection to an HTTPS origin

let endpoint = TCP.Endpoint.host("example.com", Port.from(443).try)
let connection = TLS.connect(endpoint, TLS.ClientConfig {
  serverName: "example.com",
  alpn: ["http/1.1"]
}).try

function sendAll

Sends every plaintext byte through the TLS stream.

sendAll(connection, data)

function receiveChunk

Receives one decrypted chunk no larger than limit.

receiveChunk(connection, limit)

function close

Idempotently closes the TLS stream.

close(connection)

function closed?

closed?(connection)

Returns: Bool — whether the TLS connection owner has stopped