(std net)

Reference

Overview

TCP networking abstractions exposing bidirectional connections as paired input and output ports.

(import (std net))
(import (std ports))

;; Client workflow: send request, half-close write half, read response.
(match (tcp-connect "127.0.0.1" 8080)
  ((Ok (Tuple in out))
   (write-bytes! out request)
   (flush-port out)
   (shutdown! out)              ; Send FIN packet
   (read-some in))              ; Read response payload
  ((Err e) None))
;; Server loop: accept connections until the listener closes.
(: serve (-bjo-> Listener Symbol))
(defbjo (serve l)
  (let go ()
    (match (sync (choose (wrap (accept-evt l) Some)
                         (wrap (listener-closed l) (fun (_) None))))
      ((Some (Ok conn)) (spawn (handle conn)) (go))
      ((Some (Err e))   (log (str "accept failed: " (.-Message e))) 'failed)
      (None             'stopped))))

A TCP connection is represented as a (Tuple InputPort OutputPort). Rather than exposing raw socket handles, connections integrate directly with (std ports) abstractions. Network protocols can be developed generically over ports, enabling unit testing with in-memory byte-pipe instances.

Connection I/O is managed using (std ports) and prelude functions, including read-some, read-bytes-evt, write-bytes!, flush-port, shutdown!, and limited.

Socket lifecycle. The underlying network socket is disposed when both the input and output ports are closed, or when the owning concurrency scope terminates. Closing one port direction does not terminate the opposite direction, supporting half-closed communication patterns.

Scope management. Connections created via tcp-connect or stream->ports are scoped to the ambient concurrency context. Connections produced by tcp-listen and accept belong to the listener’s scope. Exiting the scope terminates the listener and forcibly closes any active accepted connections.

CML Event semantics. Accepted incoming connections are buffered at the listener level. accept-evt is a composable CML event: if an alternative branch in choose synchronizes first, no connection is consumed, leaving it available for subsequent synchronization.

Nagle’s algorithm is disabled by default (NoDelay = true). flush-port transmits buffered bytes immediately.

See BjolangRuntime/BjoNet.cs for implementation details.

See also: tcp-connect, tcp-listen, accept-evt, accept, close-listener!, peer-address

Reference

Types

Functions

Types

Listener

type alias ↑ Types

A TCP listening socket that yields incoming connections via CML events.

See also: tcp-listen, accept-evt, accept, close-listener!, listener-closed

Functions

tcp-connect

function ↑ Functions

(: tcp-connect (-bjo-> string int (Result Exception (Tuple InputPort OutputPort))))
(tcp-connect host port)

Establishes an outbound TCP connection to a host and port, returning a port pair.

host
Host name or IP address string (e.g. "127.0.0.1" or "::1").
port
TCP port number (0–65535).
returns
(Ok (Tuple in out)) on success, or (Err e) on connection or DNS resolution failure.
raises Bjolang.Runtime.ScopeEnded
When called outside an ambient concurrency scope.
(with-deadline (seconds 5)
  (tcp-connect "example.com" 80))

Hostnames are resolved and IP addresses attempted sequentially until a connection succeeds. Connections are owned by the ambient concurrency scope and closed upon scope exit if not closed explicitly. Respects ambient cancellation tokens and deadlines.

See also: tcp-listen, stream->ports, peer-address, shutdown!

stream->ports

function ↑ Functions

(: stream->ports (-> Stream (#:peer string) (Tuple InputPort OutputPort)))
(stream->ports s #:peer "")

Wraps a bidirectional .NET Stream into an input and output port pair.

s
A bidirectional .NET Stream instance.
#:peer
Optional peer address string returned by peer-address (defaults to empty string).
returns
A tuple containing the input port and output port sharing the stream.
raises Bjolang.Runtime.ScopeEnded
When called outside an ambient concurrency scope.

Coordinates disposal across both port halves: the stream is disposed only when both the input and output ports are closed, or when the owning scope exits.

See also: tcp-connect, peer-address, stream->input-port, stream->output-port

tcp-listen

function ↑ Functions

(: tcp-listen (-> string int (#:backlog int) (Result Exception Listener)))
(tcp-listen host port #:backlog 128)

Binds and listens for incoming TCP connections on the specified host and port.

host
Host name or IP address string to bind.
port
TCP port number to bind (0 assigns an ephemeral port).
#:backlog
Maximum length of the pending connections queue (defaults to at least 1).
returns
(Ok listener) on success, or (Err e) on bind or resolution failure.
raises Bjolang.Runtime.ScopeEnded
When called outside an ambient concurrency scope.
(match (tcp-listen "127.0.0.1" 0)
  ((Ok l) (log (str "listening on " (int->string (listener-port l)))))
  ((Err e) (log (.-Message e))))

The listener is owned by the ambient concurrency scope. Scope exit forcibly closes the listening socket and any open accepted connections. Use close-listener! for graceful drain operations.

See also: accept-evt, accept, listener-port, close-listener!

listener-port

function ↑ Functions

(: listener-port (-> Listener int))
(listener-port l)

Returns the local port number assigned to the listener.

l
The TCP listener instance.
returns
The bound TCP port number.

Remains accessible after the listener is closed.

See also: tcp-listen

accept-evt

function ↑ Functions

(: accept-evt (-> Listener (Event (Result Exception (Tuple InputPort OutputPort)))))
(accept-evt l)

Returns a CML event that accepts the next incoming connection on the listener.

l
The TCP listener instance.
returns
An event yielding (Ok (Tuple in out)), or (Err e) on socket failure.

First-class CML event. If another branch in choose synchronizes first, no connection is consumed. The event is ephemeral: repeated synchronizations yield new connections. Socket errors yield an Err result.

See also: accept, listener-closed, close-listener!, tcp-listen

listener-closed

function ↑ Functions

(: listener-closed (-> Listener (Event Unit)))
(listener-closed l)

Returns a CML event that triggers when the listener has ceased accepting connections.

l
The TCP listener instance.
returns
An event enabled once the listener is closed.

Triggers when close-listener! is called or when the owning concurrency scope exits.

See also: close-listener!, accept-evt

accept

function ↑ Functions

(: accept (-> Listener (Tuple InputPort OutputPort)))
(accept l)

Accepts the next incoming connection, suspending or blocking until available.

l
The TCP listener instance.
returns
A tuple containing the input and output ports of the accepted connection.
raises System.Net.Sockets.SocketException
When an underlying socket error occurs.

Synchronizes on accept-evt. Suspends cooperatively within a bjoroutine; blocks the thread in standard synchronous code.

See also: accept-evt, listener-closed

close-listener!

function ↑ Functions

(: close-listener! (-> Listener void))
(close-listener! l)

Gracefully stops accepting new connections while preserving existing active connections.

l
The TCP listener instance.

Closes the listening socket and enables listener-closed. Existing active connections remain open until closed by their respective handlers. Idempotent.

See also: listener-closed, tcp-listen

peer-address

function ↑ Functions

(: peer-address (-> InputPort (Option string)))
(peer-address p)

Returns the remote IP address and port of a connection’s input port.

p
Input port of a TCP connection.
returns
(Some address) formatted as IP:port, or None if not a network connection.

Returns None for non-network ports, including files, pipes, and limited wrappers.

See also: tcp-connect, accept-evt, stream->ports