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
hostStringportNet.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
connectTimeoutDurationoptionalnoDelay?BooloptionalkeepAlive?BooloptionalsendBufferIntegeroptionalreceiveBufferIntegeroptional
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
backlogIntegeroptionalreuseAddress?BooloptionalnoDelay?BooloptionalkeepAlive?BooloptionalsendBufferIntegeroptionalreceiveBufferIntegeroptional
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
hostStringportNet.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
sourceEndpointdataBinary
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?BooloptionalmulticastTtlIntegeroptionalmulticastLoopback?BooloptionalreceiveTimeoutDurationoptional
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
pathString
record ConnectOptions
Connection and read deadlines for a local IPC client.
Fields
connectTimeoutDurationoptionalreceiveTimeoutDurationoptional
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
backlogIntegeroptionalremoveStale?BooloptionalacceptTimeoutDurationoptionalreceiveTimeoutDurationoptional
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
serverNameStringverify?Booloptionalalpn[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