TCP
TCP is the plain-transport entrypoint in Reseau. The same connect and listen surface supports both concrete socket addresses and hostname-based string addresses. Read Name Resolution for the resolver and policy objects behind the string-address overloads.
- Address Model
- Connections and Listeners
- Stream I/O and Lifecycle
- Deadlines, Socket Options, and Address Inspection
- Where To Go Next
Address Model
Use concrete addresses when you already know the exact family and endpoint you want to target. Reseau exposes both IPv4 and IPv6 address snapshots:
Reseau.TCP.SocketAddr — Type
SocketAddrAbstract network endpoint type for TCP socket addresses.
Reseau.TCP.SocketAddrV4 — Type
SocketAddrV4IPv4 endpoint snapshot.
The address bytes are stored in presentation order and the port is stored in host byte order. Conversion to platform sockaddr structs happens lazily when a socket operation actually needs one.
Reseau.TCP.SocketAddrV6 — Type
SocketAddrV6IPv6 endpoint snapshot.
scope_id is used for scoped link-local addresses and is preserved all the way down to the platform sockaddr representation so bind/connect can target the same interface the caller selected.
Reseau.TCP.loopback_addr — Function
loopback_addr(port) -> SocketAddrV4Convenience constructor for 127.0.0.1:port.
Reseau.TCP.any_addr — Function
any_addr(port) -> SocketAddrV4Convenience constructor for 0.0.0.0:port, typically used for wildcard binds.
Reseau.TCP.loopback_addr6 — Function
loopback_addr6(port; scope_id=0) -> SocketAddrV6Convenience constructor for [::1]:port.
Reseau.TCP.any_addr6 — Function
any_addr6(port; scope_id=0) -> SocketAddrV6Convenience constructor for the IPv6 wildcard bind address [::]:port.
Concrete addresses are especially useful when you want to bind explicitly to a family or pass a preselected local address to outbound dialing.
Connections and Listeners
The core connection surface is small and intentionally transport-focused:
Reseau.TCP.Conn — Type
ConnUser-facing connected TCP stream.
Reads and writes are forwarded to IOPoll, which means blocking operations are actually readiness waits against the shared low-level poller rather than thread-per-socket blocking syscalls. Because Conn <: IO, standard Base stream helpers like read, read!, readbytes!, eof, and write apply directly.
Reseau.TCP.Listener — Type
ListenerUser-facing passive TCP listener.
Accepted children are returned as Conn values whose underlying sockets are already non-blocking, poll-registered, and configured with the default TCP options Reseau wants.
Reseau.TCP.connect — Function
connectConnect a TCP client using either a concrete SocketAddr or a string-address overload added later in the file load order.
Reseau.TCP.listen — Function
listenCreate a TCP listener from either a concrete SocketAddr or a string-address overload added later in the file load order.
Reseau.TCP.accept — Function
acceptAccept one inbound Conn from a TCP.Listener.
For "host:port" dialing, the string-address overloads accept:
timeout_nsdeadline_nslocal_addrfallback_delay_nsresolverpolicy
Those knobs feed the resolver layer described in Name Resolution, while the actual socket lifecycle still lands in the same TCP.Conn and TCP.Listener types.
Stream I/O and Lifecycle
TCP.Conn follows Julia's standard stream conventions for read!, write, and close, while still exposing explicit half-close helpers when you need them:
Base.read! — Method
read!(conn, buf) -> bufRead exactly length(buf) bytes into buf or throw EOFError.
Because Conn <: IO, Base's generic read! implementation already supports mutable byte views like @view bytes[2:5] in addition to plain vectors.
Use readbytes! or readavailable when you want a count-returning read that may stop early.
Base.readbytes! — Method
readbytes!(conn, buf, nb=length(buf); all::Bool=true) -> IntRead up to nb bytes into buf, returning the byte count.
Unlike read!(conn, buf), this API may return after a short read or EOF. It is the count-returning TCP read entrypoint once TCP.Conn follows Julia's IO contract.
If all is true (the default), the call keeps reading until nb bytes have been transferred, EOF is reached, or an error occurs. If all is false, at most one underlying socket read is performed.
Resizable Vector{UInt8} buffers grow when needed, matching Julia's standard readbytes! behavior. Fixed-size contiguous byte views must satisfy nb <= length(buf).
Base.readavailable — Method
readavailable(conn) -> Vector{UInt8}Read and return the bytes that are currently ready without requiring a full-buffer exact read.
Base.isopen — Method
isopen(conn) -> BoolReturn true while conn still owns an open socket.
Base.isopen — Method
isopen(listener) -> BoolReturn true while listener still owns an open listening socket.
Base.write — Method
write(conn, buf) -> IntWrite all bytes from buf and return the number of bytes written.
On success, the return value is always length(buf). If the socket cannot currently accept data, the call waits for write readiness and resumes until the entire buffer has been written or an error/deadline interrupts the operation.
Base.close — Method
close(conn)Close the connection. Repeated closes are treated as no-ops.
Base.close — Method
close(listener)Close the listening socket. Repeated closes are treated as no-ops.
Reseau.TCP.closeread — Function
closeread(conn)Shut down the read side of the TCP connection.
Base.closewrite — Method
closewrite(conn)Shut down the write side of the TCP connection.
The key contract is:
read!(conn, buf)fillsbufor throwsEOFError, just like other JuliaIOtypes.readbytes!(conn, buf, nb)andreadavailable(conn)are the count-returning entrypoints when you want short-read behavior.write(conn, buf)writes the full payload unless an error or deadline interrupts the operation.close(conn)andclose(listener)are idempotent, which keeps cleanup paths safe infinallyblocks.isopen(conn)andisopen(listener)report whether the underlying socket is still live.
Deadlines, Socket Options, and Address Inspection
Deadline management lives on the live connection, not in helper tasks or external timeout wrappers:
Reseau.TCP.set_deadline! — Function
set_deadline!(conn, deadline_ns)Set both read and write deadlines on conn.
deadline_nsis an absolute monotonic timestamp in nanoseconds, using the same clock astime_ns().deadline_ns == 0disables both deadlines.deadline_ns <= time_ns()marks both sides as immediately timed out.
After the deadline is reached, blocking read!/write operations fail with DeadlineExceededError until the deadline is cleared or moved forward.
set_deadline!(listener, deadline_ns)Set the accept deadline on listener.
deadline_nsuses the same absolute monotonictime_ns()clock as connection deadlines.deadline_ns == 0disables accept timeouts.deadline_ns <= time_ns()causes the next blockingacceptto time out immediately.
This affects accept(listener) only.
Reseau.TCP.set_read_deadline! — Function
set_read_deadline!(conn, deadline_ns)Set only the read deadline on conn.
- Uses absolute monotonic nanoseconds (
time_ns()clock). deadline_ns == 0disables read timeouts.deadline_ns <= time_ns()causes read waits to time out immediately.
This affects read! wait paths only.
Reseau.TCP.set_write_deadline! — Function
set_write_deadline!(conn, deadline_ns)Set only the write deadline on conn.
- Uses absolute monotonic nanoseconds (
time_ns()clock). deadline_ns == 0disables write timeouts.deadline_ns <= time_ns()causes write waits to time out immediately.
This affects write wait paths only.
Reseau.TCP.DeadlineExceededError — Type
DeadlineExceededErrorRaised when blocking TCP I/O or accept(listener) exceeds the active deadline.
Catch TCP.DeadlineExceededError when a deadline set by set_deadline!, set_read_deadline!, or set_write_deadline! expires. This aliases the underlying poller timeout type so downstream code does not need to depend on Reseau.IOPoll directly.
Reseau.TCP.set_nodelay! — Function
set_nodelay!(conn, enabled=true)Enable or disable TCP_NODELAY on conn.
Reseau.TCP.set_keepalive! — Function
set_keepalive!(conn, enabled=true)Enable or disable SO_KEEPALIVE on conn.
Reseau.TCP.local_addr — Function
local_addr(conn) -> Union{Nothing, SocketAddr}Return the cached local endpoint for conn, if known.
local_addr(listener) -> Union{Nothing, SocketAddr}Return the listener's bound local endpoint.
This is an alias for addr(listener).
Reseau.TCP.remote_addr — Function
remote_addr(conn) -> Union{Nothing, SocketAddr}Return the cached remote endpoint for conn, if known.
Reseau.TCP.addr — Function
addr(listener) -> Union{Nothing, SocketAddr}Return the listener's bound local endpoint, if known.
Use absolute monotonic nanoseconds from time_ns() for deadline APIs. Setting a deadline to 0 clears it, while setting it to a time in the past makes the next blocking wait time out immediately.
Deadline expiry is surfaced as TCP.DeadlineExceededError. Catch that alias instead of reaching into Reseau.IOPoll directly:
try
TCP.set_read_deadline!(conn, time_ns() + 100_000_000)
read!(conn, buf)
catch err
if err isa TCP.DeadlineExceededError
TCP.set_read_deadline!(conn, 0) # clear or move the deadline before retrying
else
rethrow()
end
endListeners use the same set_deadline! name for accept deadlines. That deadline applies only to accept(listener); established connections still use their own per-connection deadline state. local_addr(listener) is also available as a discoverable alias for addr(listener).
Where To Go Next
- Read TLS for the TLS wrapper layer that reuses the same transport and deadline model.
- Read Name Resolution for the advanced resolver controls that sit behind string-address dialing.
- Read API Reference for the canonical docstrings for the entire TCP surface.