Skip to content
CryoCryo home
Stdlibnet::socket

tcp

import std::net::socket::tcp; · source

Types

TcpListener

type struct TcpListener {
    fd: i32;

    static bind(local: SocketAddr) -> Result<TcpListener, IoError>;
    static from_fd(sock: i32) -> TcpListener;
    raw_fd(&this) -> i32;
    set_nonblocking(mut &this, on: boolean) -> Result<(), IoError>;
    local_addr(&this) -> Result<SocketAddr, IoError>;
}

TcpListener::bind is the one plain call in this file — binding does not wait. Everything else is a future with a start(...) constructor:

import std::net::socket::tcp;
import std::net::addr::socket_addr;
import std::io::buf;

async function serve(addr: SocketAddr) -> Result<(), IoError> {
    mut listener: TcpListener = TcpListener::bind(addr)?;
    loop {
        mut accepted: TcpAccepted = await TcpAccept::start(listener);
        listener = accepted.take_listener();
        mut conn: BufStream<TcpStream> = BufStream::<TcpStream>::of(accepted.take_result()?);
        await handle(conn);
    }
}

TcpAccept puts the sockets it produces in non-blocking mode, and the listener closes its descriptor through an inherent drop.

Properties

PropertyType
fdi32

Constructors

static bind(local: SocketAddr) -> Result<TcpListener, IoError>;

Bind + listen on local (IPv4 or IPv6). Sets SO_REUSEADDR so restarts don't wait out the TIME_WAIT window. Backlog defaults to 128, the same number Linux uses for /proc/sys/net/core/somaxconn these days.

static from_fd(sock: i32) -> TcpListener;

Wrap a raw listening descriptor. The caller transfers ownership; drop closes it. Used by TcpAccept to hand the listener back.

Methods

raw_fd(&this) -> i32;

Borrow the underlying descriptor without transferring ownership.

set_nonblocking(mut &this, on: boolean) -> Result<(), IoError>;

Put the listener in non-blocking mode, where accept returns WouldBlock instead of sleeping the calling thread. Required before this listener is used with TcpAccept.

local_addr(&this) -> Result<SocketAddr, IoError>;

The local address the listener is bound to. After bind(.., 0) this reports the kernel-assigned ephemeral port - the only way to learn it (and the hermetic alternative to guessing a fixed port). Handles both v4 and v6 listeners.

TcpStream

type struct TcpStream {
    fd: i32;

    static from_fd(sock: i32) -> TcpStream;
    raw_fd(&this) -> i32;
    shutdown_write(mut &this) -> Result<(), IoError>;
    set_nonblocking(mut &this, on: boolean) -> Result<(), IoError>;
}

A connected socket. You get one from TcpConnect or TcpAccept, both of which leave it in non-blocking mode; a stream adopted with from_fd needs set_nonblocking(true) before it is used with a future. shutdown_write half-closes so the peer sees EOF. It closes its descriptor through an inherent drop.

Properties

PropertyType
fdi32

Constructors

static from_fd(sock: i32) -> TcpStream;

Wrap a raw file descriptor. The caller transfers ownership; drop will close it. Used by TcpAccept to hand over the socket it produced, and to leave a closed placeholder behind when a future takes the real one.

Methods

raw_fd(&this) -> i32;

Borrow the underlying file descriptor without transferring ownership. The TcpStream still closes it on drop. Used by net::tls to hand the fd to OpenSSL's socket BIO (which is created BIO_NOCLOSE, so the fd stays this stream's to close).

shutdown_write(mut &this) -> Result<(), IoError>;

Close the write half. Signals "no more from me" without tearing down the read path. Useful for protocols where the client sends then reads to EOF.

set_nonblocking(mut &this, on: boolean) -> Result<(), IoError>;

Put the socket in non-blocking mode, where reads and writes report WouldBlock instead of sleeping the calling thread. Required before this stream is used with TcpRead/TcpWrite — a blocking socket would stall an executor's whole worker thread inside the syscall.

The futures

Every operation that can wait is one of these four, each with a start(...) constructor. Each attempts its syscall on the non-blocking socket, and if the socket is not ready registers the polling task's waker with the current Reactor and returns Pending. Registering after the failed attempt is what makes the race safe: the reactor arms level-triggered, so readiness that arrived in between is still reported. These futures park only where a reactor exists — an Executor's worker threads — and polling one anywhere else panics rather than parking a task that could never be woken.

Dropping a future mid-operation releases its reactor registration and, for TcpConnect, closes the half-connected socket — see cancellation is a drop. Only the direction that future owned is cancelled, so a write parked on the same socket keeps waiting.

TcpConnect

type struct TcpConnect {
    fd:      i32;
    addr:    [u8;
    28];
    addrlen: u32;
    err:     IoError;
    rt:      Reactor*;

    static start(remote: SocketAddr) -> TcpConnect;
}

Completes with Result<TcpStream, IoError>. The socket is opened and the handshake started at construction; each poll asks the OS whether it finished, parking on writability in between.

Properties
PropertyType
fdi32
addr[u8
28]
addrlenu32
errIoError
rtReactor*
Constructors
static start(remote: SocketAddr) -> TcpConnect;

Open a non-blocking socket and start connecting to remote.

TcpAccept

type struct TcpAccept {
    listener: TcpListener;
    rt:       Reactor*;

    static start(listener: TcpListener) -> TcpAccept;
}

Completes with a TcpAccepted: the listener back, plus the new stream or the error.

Properties
PropertyType
listenerTcpListener
rtReactor*
Constructors
static start(listener: TcpListener) -> TcpAccept;

Begin an accept on listener, which this future owns until it completes.

TcpRead

type struct TcpRead {
    stream: TcpStream;
    buf:    Array<u8>;
    rt:     Reactor*;

    static start(stream: TcpStream, buf: Array<u8>) -> TcpRead;
}

Completes with a TcpIo: the stream and buffer back, with outcome() the byte count — 0 at EOF. A read fills buf's [0, length) and truncates it to what arrived, so hand in one sized with resize.

Properties
PropertyType
streamTcpStream
bufArray<u8>
rtReactor*
Constructors
static start(stream: TcpStream, buf: Array<u8>) -> TcpRead;

Begin a read on stream, filling buf — both owned by this future until it completes.

TcpWrite

type struct TcpWrite {
    stream: TcpStream;
    buf:    Array<u8>;
    rt:     Reactor*;

    static start(stream: TcpStream, buf: Array<u8>) -> TcpWrite;
}

Completes with a TcpIo whose outcome() is the bytes accepted, which may be fewer than offered — the caller sends the remainder in another operation.

Properties
PropertyType
streamTcpStream
bufArray<u8>
rtReactor*
Constructors
static start(stream: TcpStream, buf: Array<u8>) -> TcpWrite;

Begin a write of every byte in buf on stream — both owned by this future until it completes.

The outcomes

type struct TcpIo {
    stream: TcpStream;
    buf:    Array<u8>;
    result: Result<u64, IoError>;

    take_stream(mut &this) -> TcpStream;
    take_buf(mut &this) -> Array<u8>;
    outcome(&this) -> Result<u64, IoError>;
}
type struct TcpAccepted {
    listener: TcpListener;
    result:   Result<TcpStream, IoError>;

    take_listener(mut &this) -> TcpListener;
    take_result(mut &this) -> Result<TcpStream, IoError>;
}

The outputs hand their handles back through take_* rather than by field: a TcpStream closes its descriptor when dropped, so the compiler will not let a field be moved out of an outcome that would still drop it. take_stream swaps in a closed placeholder, leaving nothing behind to close. outcome() is how many bytes moved, or why none did.

TcpIo

Properties
PropertyType
streamTcpStream
bufArray<u8>
resultResult<u64, IoError>
Methods
take_stream(mut &this) -> TcpStream;

Take the socket back. Calling it twice yields a closed stream the second time — the outcome holds the socket exactly once.

take_buf(mut &this) -> Array<u8>;

Take the buffer back. After a read it holds exactly the bytes that arrived; after a write it is untouched, so a caller with a short write still has the bytes it has not sent yet. Calling it twice yields an empty buffer the second time.

outcome(&this) -> Result<u64, IoError>;

How many bytes moved, or why none did.

TcpAccepted

Properties
PropertyType
listenerTcpListener
resultResult<TcpStream, IoError>
Methods
take_listener(mut &this) -> TcpListener;

Take the listener back, so the next accept can be started on it.

take_result(mut &this) -> Result<TcpStream, IoError>;

Take the accepted connection, or the error that prevented one.

Trait implementations

TcpStream

implement trait Drop for struct TcpStream
implement trait AsyncTransport for struct TcpStream

TcpConnect

implement trait Future for struct TcpConnect
implement trait Drop for struct TcpConnect

TcpAccept

implement trait Future for struct TcpAccept
implement trait Drop for struct TcpAccept

TcpRead

implement trait Future for struct TcpRead
implement trait Drop for struct TcpRead

TcpWrite

implement trait Future for struct TcpWrite
implement trait Drop for struct TcpWrite

AsyncTransport is what lets BufStream<TcpStream> exist — its read_into and write_from are TcpRead and TcpWrite with the move-out/move-back handled inside.