Every failure of the network or the operating system is TcpErr(IOErr), so
results compare with ==: result == Err(TcpErr(ConnectionRefused)).
Timeouts are Durations. The wait to connect or to accept bounds that one
call. The connection it produces holds its own I/O timeout, which bounds
each later read or write as a whole. Duration.zero expires immediately,
and an expired timeout is always TcpErr(TimedOut).
Bind an address and listen for connections. Port zero asks the operating
system for a free port, which [Listener.local_port!] reports. The
timeout covers hostname resolution.
listener = Tcp.listen!("127.0.0.1", 0, Duration.seconds(5))?
port = listener.local_port!()?
connect_timeout bounds this call, across hostname resolution and every
address the name resolves to. io_timeout is the timeout the new
Connection holds for its reads and writes.
A port nobody listens on is Err(TcpErr(ConnectionRefused)) once the
operating system reports it. Windows retries for about two seconds
first, so a shorter connect_timeout gives Err(TcpErr(TimedOut)) there.
The socket is closed when the last reference to the listener is
released, or earlier by [close!]. Copies of a listener share one
socket, so closing one closes them all.
accept_timeout bounds this call only: NoTimeout waits
indefinitely, and After(duration) gives up with
Err(TcpErr(TimedOut)), after which the listener can accept again.
io_timeout is the timeout the new Connection holds for its reads
and writes; a connection never inherits the accept wait.
A buffered TCP connection, with the I/O timeout and line limit its
reads and writes use.
The connection is closed when the last reference to it is released.
Copies of a connection share one socket and one buffer, so every read,
whether of lines, delimited bytes or binary data, continues where the
previous one stopped. Connection.with_timeout and
Connection.with_line_limit change the settings of the copy they return,
not the socket.
Every read ends the same way: once the peer has closed its side and all
data has been returned, the next read is Err(EndOfInput). An empty
Ok is real data, such as an empty line.
A read that times out consumes nothing. Bytes that had arrived stay
buffered for the next read, so a client may simply read again. A write
that times out may have sent any prefix of its bytes: drop the
connection unless the protocol can resynchronise.
The same connection with another limit, in bytes, on one record read
by [read_until!], [read_line!] or Connection.lines. The delimiter
or line terminator counts towards the limit. The default is
1,048,576 (1 MiB).
Read at most max_bytes bytes, returning as soon as any have
arrived. Short reads are valid. Asking for zero bytes returns
Ok([]) without waiting; otherwise the result is never empty, and a
closed peer is Err(EndOfInput).
Read exactly count bytes. Zero succeeds without waiting.
If the peer closes before count bytes arrive the result is
Err(UnexpectedEndOfInput). The bytes that did arrive are not
consumed: [read_up_to!] returns them.
Read bytes through and including the next delimiter.
If the peer closes first, the bytes before the end are returned
without a delimiter, and the read after that is Err(EndOfInput).
So the result is never empty, and its last byte shows whether the
delimiter arrived.
A record longer than the connection's line limit is
Err(ReadLimitExceeded(limit)). The rest of that record, through
its delimiter, is then discarded before the next read returns, as
part of that read and within its timeout.
field = conn.read_until!('|')?
read_line! : Connection => Try(Str, [EndOfInput, ReadLimitExceeded(U64), BadUtf8({ problem : Utf8Problem, index : U64 }), TcpErr(IOErr)])
Read a line of text.
A line ends at \n. The terminator is not returned, and one \r
before it is removed. If the peer closes without a final \n the
last line is still returned; after that the result is
Err(EndOfInput). An empty line is Ok("").
A line longer than the connection's line limit is
Err(ReadLimitExceeded(limit)), and a line that is not valid UTF-8
is BadUtf8. Either way that line is skipped and the next call
reads the line after it. For the bytes of a line, use
conn.read_until!('\n').
Lazily read this connection as non-empty chunks of at most 64 KiB,
each returned as soon as it arrives. Chunk boundaries do not
correspond to the peer's writes, records, or text encoding
boundaries. For a chosen size, call [read_up_to!] in a loop.
Building the stream reads nothing; each item is one read with the
connection's timeout. The stream ends when the peer closes. A
TcpErr item, including TcpErr(TimedOut), is the last one; the
connection stays usable and a new stream may be started.
The stream holds no data of its own, so it can be mixed with the
other reads and with writes. It keeps the connection open until it
has finished or is released.
Lazily read this connection a line at a time, as [read_line!] does.
Building the stream reads nothing; each item is one read with the
connection's timeout and line limit. The stream ends when the peer
closes. BadUtf8 and ReadLimitExceeded items concern one line, and
the stream continues with the next. A TcpErr item, including
TcpErr(TimedOut), is the last one; the connection stays usable, so
a client that tolerates idle periods calls conn.lines() again.
The stream holds no data of its own, so it can be mixed with the
other reads and with writes, and leaving the loop early loses
nothing. It keeps the connection open until it has finished or is
released.