Net

Networking namespaces for IP addresses, sockets, TCP, UDP, and DNS.

std.net is a namespace aggregator for owned socket handles, typed addresses, and async TCP, UDP, and DNS helpers. The canonical APIs live in focused submodules:

import std.net.ipaddr;
import std.net.socket;
import std.net.tcp;
import std.net.udp;
import std.net.dns;

std.net still re-exports the submodule namespaces and NetError, so net.ipaddr.SocketAddr and net.NetError.InvalidAddress are valid. Prefer the submodule imports in examples and application code.

Addresses

Ipv4Addr, Ipv6Addr, IpAddr, and SocketAddr are copyable value types. Use typed constructors for known addresses and parse for text input.

import std.net.ipaddr;

fn main() {
    let ip = try ipaddr.Ipv4Addr.parse("127.0.0.1");
    let addr = try ipaddr.SocketAddr.parse("127.0.0.1:8080");
    let octets = ip.octets();

    assert octets[0] == 127 as u8;
    assert addr.port() == 8080 as u16;
}

IPv6 socket addresses use brackets in text form, for example [::1]:8080. Ipv4Addr.octets() returns the four IPv4 bytes in network order; the old octet0() through octet3() helpers are not part of the public surface.

Sockets

socket.Socket is the low-level owned endpoint. It exposes descriptor access, binding, listening, accepting, connecting, raw send and receive operations, and address queries. fd() borrows the descriptor; take_fd() transfers ownership.

import std.net.ipaddr;
import std.net.socket;

async fn main() {
    let server = try socket.Socket.open(.Ipv4, .Stream);
    try server.bind(ipaddr.SocketAddr.localhost(0 as u16));
    try server.listen(128);

    let peer = try await server.accept();
    _ = peer.fd();
}

TCP And UDP

tcp.TcpListener accepts tcp.TcpStream values. tcp.TcpStream implements aio.Stream, so it works with generic std.aio helpers.

import std.net.ipaddr;
import std.net.tcp;

async fn main() {
    let listener = try tcp.TcpListener.bind(ipaddr.SocketAddr.localhost(0 as u16));
    let addr = try listener.local_addr();
    let accepted = listener.accept();
    let stream = try await tcp.TcpStream.connect(addr);
    let peer = try await accepted;

    try peer.shutdown();
    try stream.shutdown();
}

UDP remains datagram-oriented: send_to and recv_from carry peer addresses, while connected UDP uses connect, send, and recv.

import std.bytes;
import std.net.ipaddr;
import std.net.udp;

async fn main() {
    let socket = try udp.UdpSocket.bind(ipaddr.SocketAddr.localhost(0 as u16));
    let addr = try socket.local_addr();
    _ = try await socket.send_to(bytes.Bytes("x"), addr);
}

DNS

dns.resolve(host, port) runs on the runtime resolver worker and returns future.Future<Array<ipaddr.SocketAddr> throws(io.IOError | AllocError)>. Callers choose an address or apply their own retry and IPv4/IPv6 policy.

import std.net.dns;

async fn main() {
    let addrs = try await dns.resolve("localhost", 80 as u16);
    _ = addrs.length;
}

Runtime socket failures are reported as io.IOError; parse-time address failures use net.NetError.InvalidAddress or net.NetError.InvalidPort.

API Map

NamespaceMain itemsPurpose
std.net.ipaddrAddressFamily, Ipv4Addr, Ipv6Addr, IpAddr, SocketAddrTyped address values and parsing.
std.net.socketSocketKind, SocketLow-level owned socket endpoint.
std.net.tcpTcpListener, TcpStreamAsync TCP listener and stream handles.
std.net.udpUdpSocketAsync UDP socket operations.
std.net.dnsresolveAsync host resolution.
std.netsubmodule namespaces, NetErrorAggregator and shared networking errors.

Flat names such as net.SocketAddr, net.TcpStream, net.UdpSocket, and net.resolve are no longer the documented API.