std.net.Address em Zig — Referência e Exemplos

std.net.Address — Endereços de Rede

O tipo std.net.Address representa um endereço de rede completo (endereço IP e porta) usado para identificar endpoints em comunicações de rede. Ele suporta IPv4, IPv6 e Unix domain sockets, e fornece funções para parsing, formatação e resolução de nomes DNS.

Visão Geral

const std = @import("std");
const net = std.net;
const Address = net.Address;

Estrutura

pub const Address = union(enum) {
    ipv4: std.posix.sockaddr.in,
    ipv6: std.posix.sockaddr.in6,
    un: std.posix.sockaddr.un,
};

O tipo é uma tagged union que pode representar:

  • IPv4: endereço de 32 bits + porta de 16 bits
  • IPv6: endereço de 128 bits + porta de 16 bits + flow info + scope id
  • Unix: caminho do socket no sistema de arquivos

Funções Principais

Criação de Endereços

// Parse de string IPv4
pub fn parseIp4(ip: []const u8, port: u16) !Address

// Parse de string IPv6
pub fn parseIp6(ip: []const u8, port: u16) !Address

// Parse automático (detecta IPv4/IPv6)
pub fn parseIp(ip: []const u8, port: u16) !Address

// Resolve hostname via DNS
pub fn resolveIp(name: []const u8, port: u16) !Address

// Endereço para "qualquer" interface (0.0.0.0 ou ::)
pub fn initIp4(addr: [4]u8, port: u16) Address
pub fn initIp6(addr: [16]u8, port: u16) Address

// Unix domain socket
pub fn initUnix(path: []const u8) !Address

Acesso a Componentes

// Retorna a porta
pub fn getPort(self: Address) u16

// Define a porta
pub fn setPort(self: *Address, port: u16) void

// Retorna o endereço como bytes
pub fn getOsSockLen(self: Address) std.posix.socklen_t

Comparação e Formatação

// Compara dois endereços
pub fn eql(a: Address, b: Address) bool

// Formata para impressão
pub fn format(self: Address, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void

Operações de Socket

// Cria um servidor TCP neste endereço
pub fn listen(self: Address, options: ListenOptions) !net.Server

// Conecta a este endereço via TCP
pub fn tcpConnectToAddress(address: Address) !net.Stream

Exemplo 1: Trabalhando com Endereços IPv4 e IPv6

const std = @import("std");
const net = std.net;

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    // IPv4
    const addr_local = try net.Address.parseIp4("127.0.0.1", 8080);
    const addr_rede = try net.Address.parseIp4("192.168.1.100", 3000);
    const addr_qualquer = net.Address.initIp4(.{ 0, 0, 0, 0 }, 9000);

    try stdout.print("Local:    {}\n", .{addr_local});
    try stdout.print("Rede:     {}\n", .{addr_rede});
    try stdout.print("Qualquer: {}\n", .{addr_qualquer});

    // IPv6
    const addr_loopback6 = try net.Address.parseIp6("::1", 8080);
    const addr_qualquer6 = try net.Address.parseIp6("::", 9000);

    try stdout.print("IPv6 loopback: {}\n", .{addr_loopback6});
    try stdout.print("IPv6 qualquer: {}\n", .{addr_qualquer6});

    // Parse automático
    const auto4 = try net.Address.parseIp("10.0.0.1", 80);
    const auto6 = try net.Address.parseIp("::1", 80);

    try stdout.print("Auto IPv4: {}\n", .{auto4});
    try stdout.print("Auto IPv6: {}\n", .{auto6});

    // Porta
    try stdout.print("Porta: {d}\n", .{addr_local.getPort()});
}

Exemplo 2: Resolução DNS e Verificação

const std = @import("std");
const net = std.net;

const ServicoInfo = struct {
    nome: []const u8,
    host: []const u8,
    porta: u16,
};

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();

    const servicos = [_]ServicoInfo{
        .{ .nome = "Web Local", .host = "127.0.0.1", .porta = 80 },
        .{ .nome = "API", .host = "127.0.0.1", .porta = 3000 },
        .{ .nome = "Banco", .host = "127.0.0.1", .porta = 5432 },
        .{ .nome = "Cache", .host = "127.0.0.1", .porta = 6379 },
    };

    try stdout.writeAll("=== Endereços dos Serviços ===\n\n");

    for (servicos) |servico| {
        const addr = net.Address.resolveIp(servico.host, servico.porta) catch |err| {
            try stdout.print("{s:<12} ERRO: {}\n", .{ servico.nome, err });
            continue;
        };

        try stdout.print("{s:<12} {}\n", .{ servico.nome, addr });
    }

    // Compara endereços
    try stdout.writeAll("\n=== Comparações ===\n");
    const a = try net.Address.parseIp4("127.0.0.1", 80);
    const b = try net.Address.parseIp4("127.0.0.1", 80);
    const c = try net.Address.parseIp4("127.0.0.1", 443);
    const d = try net.Address.parseIp4("192.168.1.1", 80);

    try stdout.print("127.0.0.1:80 == 127.0.0.1:80:   {}\n", .{a.eql(b)});
    try stdout.print("127.0.0.1:80 == 127.0.0.1:443:  {}\n", .{a.eql(c)});
    try stdout.print("127.0.0.1:80 == 192.168.1.1:80:  {}\n", .{a.eql(d)});
}

Exemplo 3: Servidor Multi-Endereço

const std = @import("std");
const net = std.net;

const EndpointConfig = struct {
    nome: []const u8,
    ip: []const u8,
    porta: u16,
};

fn formatarEnderecos(
    configs: []const EndpointConfig,
    allocator: std.mem.Allocator,
) !std.ArrayList(net.Address) {
    var enderecos = std.ArrayList(net.Address).init(allocator);
    errdefer enderecos.deinit();

    for (configs) |cfg| {
        const addr = net.Address.parseIp(cfg.ip, cfg.porta) catch |err| {
            std.debug.print("Erro em '{s}': {}\n", .{ cfg.nome, err });
            continue;
        };
        try enderecos.append(addr);
    }

    return enderecos;
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();

    const configs = [_]EndpointConfig{
        .{ .nome = "HTTP", .ip = "0.0.0.0", .porta = 80 },
        .{ .nome = "HTTPS", .ip = "0.0.0.0", .porta = 443 },
        .{ .nome = "Admin", .ip = "127.0.0.1", .porta = 9090 },
        .{ .nome = "Métricas", .ip = "127.0.0.1", .porta = 9091 },
    };

    var enderecos = try formatarEnderecos(&configs, allocator);
    defer enderecos.deinit();

    const stdout = std.io.getStdOut().writer();
    try stdout.writeAll("Endpoints configurados:\n");

    for (configs[0..enderecos.items.len], enderecos.items) |cfg, addr| {
        try stdout.print("  {s:<10} -> {}\n", .{ cfg.nome, addr });
    }

    // Cria endereço para binding em todas as interfaces
    const bind_all = net.Address.initIp4(.{ 0, 0, 0, 0 }, 8080);
    try stdout.print("\nBind all: {}\n", .{bind_all});
    try stdout.print("É IPv4: {}\n", .{bind_all == .ipv4});
}

Módulos Relacionados

Tutoriais e Receitas Relacionados

Continue aprendendo Zig

Explore mais tutoriais e artigos em português para dominar a linguagem Zig.