Skip to content

std.net.tcp

Blocking TCP listeners and streams.

std.net.tcp exposes a blocking TCP API. Both TcpListener and TcpStream are owned types with destructors that close their fd on scope exit; they also support defer and use mut cleanup via close_best_effort.

export struct TcpListener:
fd: c_int
export struct TcpStream:
fd: c_int
export enum NetError:
case InvalidPort
case PermissionDenied
case AddressInUse
case Interrupted
case SocketFailed(code: i32)
case BindFailed(code: i32)
case ListenFailed(code: i32)
case AcceptFailed(code: i32)
case ReadFailed(code: i32)
case WriteFailed(code: i32)
case CloseFailed(code: i32)

Both handles expose close_best_effort(self: mut view T) -> None and drop.

export def tcp_listen_ipv4(port: usize) -> Result[TcpListener, NetError]
export def accept(listener: view TcpListener) -> Result[TcpStream, NetError]

tcp_listen_ipv4 binds to 127.0.0.1:port. Ports above 65535 return InvalidPort without touching the OS.

export def stream_read(stream: view TcpStream, buf: mut view [u8]) -> Result[usize, NetError]
export def stream_read_into(stream: view TcpStream, buf: mut view ByteBuf, max: usize) -> Result[usize, NetError]
export def stream_write_all(stream: view TcpStream, bytes: view [u8]) -> Result[None, NetError]

stream_write_all loops internally until every byte has been written or an error is returned. stream_read_into grows buf with zeroed bytes once, then reuses it across calls: useful for steady request loops.

export def stream_close(stream: TcpStream) -> Result[None, NetError]
export def listener_close(listener: TcpListener) -> Result[None, NetError]
export def stream_invalid() -> TcpStream
export def stream_is_valid(stream: view TcpStream) -> bool

stream_close / listener_close consume the handle and surface the close errno. The destructor and close_best_effort paths swallow the error: call the consuming _close when you need to propagate it.

See examples/tcp-blocking for an end-to-end accept-read-respond loop.