std.net — Networking de Baixo Nível
O módulo std.net fornece primitivas de rede para comunicação via sockets TCP e UDP. Ele encapsula as APIs de sockets do sistema operacional em uma interface idiomática do Zig, com tratamento de erros explícito e suporte a IPv4 e IPv6. É a base sobre a qual o módulo std.http é construído.
Visão Geral
const std = @import("std");
const net = std.net;
O módulo é organizado em torno de três conceitos principais:
Address— Representa um endereço de rede (IP + porta)Stream— Conexão TCP bidirecional (leitura e escrita)Server— Socket de escuta que aceita conexões
Tipos Principais
net.Address
pub const Address = union(enum) {
ipv4: std.posix.sockaddr.in,
ipv6: std.posix.sockaddr.in6,
un: std.posix.sockaddr.un, // Unix domain socket
};
net.Stream
pub const Stream = struct {
handle: std.posix.socket_t,
pub fn read(self: Stream, buf: []u8) !usize
pub fn write(self: Stream, buf: []const u8) !usize
pub fn close(self: Stream) void
// Implementa interfaces de Reader e Writer
pub fn reader(self: Stream) Reader
pub fn writer(self: Stream) Writer
};
net.Server
pub const Server = struct {
pub fn accept(self: *Server) !Connection
pub fn deinit(self: *Server) void
pub const Connection = struct {
stream: Stream,
address: Address,
};
};
Funções Principais
// Resolução de endereço
pub fn Address.parseIp4(ip: []const u8, port: u16) !Address
pub fn Address.parseIp6(ip: []const u8, port: u16) !Address
pub fn Address.resolveIp(name: []const u8, port: u16) !Address
// Conexão TCP
pub fn tcpConnectToHost(allocator: Allocator, host: []const u8, port: u16) !Stream
pub fn tcpConnectToAddress(address: Address) !Stream
// Servidor TCP
pub fn Address.listen(address: Address, options: ListenOptions) !Server
Exemplo 1: Cliente TCP Simples
const std = @import("std");
const net = std.net;
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const stdout = std.io.getStdOut().writer();
// Conecta a um servidor
const stream = net.tcpConnectToHost(allocator, "example.com", 80) catch |err| {
try stdout.print("Erro de conexão: {}\n", .{err});
return;
};
defer stream.close();
try stdout.writeAll("Conectado a example.com:80\n");
// Envia requisição HTTP simples
const request =
"GET / HTTP/1.1\r\n" ++
"Host: example.com\r\n" ++
"Connection: close\r\n" ++
"\r\n";
_ = try stream.write(request);
// Lê resposta
var buf: [4096]u8 = undefined;
var total: usize = 0;
while (true) {
const n = stream.read(&buf) catch break;
if (n == 0) break;
total += n;
}
try stdout.print("Bytes recebidos: {d}\n", .{total});
}
Exemplo 2: Servidor Echo TCP
const std = @import("std");
const net = std.net;
fn handleClient(connection: net.Server.Connection) void {
defer connection.stream.close();
const reader = connection.stream.reader();
const writer = connection.stream.writer();
// Echo: lê e reenvia
var buf: [1024]u8 = undefined;
while (true) {
const n = reader.read(&buf) catch break;
if (n == 0) break;
writer.writeAll(buf[0..n]) catch break;
}
std.debug.print("Cliente desconectou: {}\n", .{connection.address});
}
pub fn main() !void {
const addr = try net.Address.parseIp4("127.0.0.1", 9000);
var server = try addr.listen(.{
.reuse_address = true,
});
defer server.deinit();
std.debug.print("Servidor echo escutando em 127.0.0.1:9000\n", .{});
// Aceita conexões em loop
while (true) {
const connection = server.accept() catch |err| {
std.debug.print("Erro ao aceitar: {}\n", .{err});
continue;
};
std.debug.print("Nova conexão de: {}\n", .{connection.address});
// Em produção, use threads ou async para múltiplos clientes
handleClient(connection);
}
}
Exemplo 3: Resolução de Endereços
const std = @import("std");
const net = std.net;
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// Parse de endereço IPv4
const addr4 = try net.Address.parseIp4("192.168.1.100", 8080);
try stdout.print("IPv4: {}\n", .{addr4});
// Parse de endereço IPv6
const addr6 = try net.Address.parseIp6("::1", 8080);
try stdout.print("IPv6: {}\n", .{addr6});
// Resolução de hostname
const resolved = net.Address.resolveIp("localhost", 3000) catch |err| {
try stdout.print("Erro na resolução: {}\n", .{err});
return;
};
try stdout.print("localhost: {}\n", .{resolved});
// Comparação de endereços
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);
try stdout.print("a == b: {}\n", .{a.eql(b)});
try stdout.print("a == c: {}\n", .{a.eql(c)});
// Porta
try stdout.print("Porta de a: {d}\n", .{a.getPort()});
}
Padrões Comuns
Timeout de Conexão
// Configura timeout via opções do socket
const stream = try net.tcpConnectToHost(allocator, "host", 80);
// Use std.posix.setsockopt para configurar SO_RCVTIMEO / SO_SNDTIMEO
Servidor Concorrente (com Threads)
const connection = try server.accept();
const thread = try std.Thread.spawn(.{}, handleClient, .{connection});
thread.detach();
Módulos Relacionados
- std.net.Stream — Conexão TCP bidirecional
- std.net.Address — Tipos de endereço
- std.http — HTTP sobre TCP
- std.io — Interfaces de I/O
- std.Thread — Concorrência para servidores