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
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, orNoneif not a network connection.
Returns None for non-network ports, including files, pipes, and
limited wrappers.
See also: tcp-connect, accept-evt, stream->ports