---
title: "Como Usar Sockets UDP em Zig"
url: "https://ziglang.com.br/receitas/como-usar-sockets-udp-em-zig/"
markdown_url: "https://ziglang.com.br/receitas/como-usar-sockets-udp-em-zig.MD"
description: "Aprenda a criar sockets UDP em Zig para enviar e receber datagramas, implementar clientes e servidores UDP usando a biblioteca padrão std.net."
date: "2026-02-21"
author: "Zig Brasil"
---

# Como Usar Sockets UDP em Zig

Aprenda a criar sockets UDP em Zig para enviar e receber datagramas, implementar clientes e servidores UDP usando a biblioteca padrão std.net.


## Introdução

UDP (User Datagram Protocol) é um protocolo de transporte leve e sem conexão. Diferente do TCP, o UDP não garante entrega, ordem ou integridade dos dados, mas oferece menor latência e overhead. É ideal para aplicações de tempo real como jogos, streaming de vídeo e DNS.

Nesta receita, você aprenderá a criar sockets UDP em Zig para enviar e receber datagramas.

## Pré-requisitos

- Zig instalado (versão 0.13+). Veja o [guia de instalação](/tutoriais/como-instalar-zig/)
- Conhecimento básico de Zig. Consulte a [introdução ao Zig](/tutoriais/introducao-ao-zig/)

## Servidor UDP Básico

Um servidor UDP escuta em uma porta e recebe datagramas de qualquer cliente:

```zig
const std = @import("std");
const net = std.net;
const posix = std.posix;

pub fn main() !void {
    // Criar socket UDP
    const sock = try posix.socket(posix.AF.INET, posix.SOCK.DGRAM, 0);
    defer posix.close(sock);

    // Vincular à porta 9000
    const addr = net.Address.initIp4(.{ 0, 0, 0, 0 }, 9000);
    try posix.bind(sock, &addr.any, addr.getOsSockLen());

    std.debug.print("Servidor UDP escutando na porta 9000...\n", .{});

    var buffer: [1024]u8 = undefined;

    while (true) {
        var src_addr: posix.sockaddr = undefined;
        var addr_len: posix.socklen_t = @sizeOf(posix.sockaddr);

        // Receber datagrama
        const bytes_received = try posix.recvfrom(
            sock,
            &buffer,
            0,
            &src_addr,
            &addr_len,
        );

        const sender = net.Address.initPosix(@alignCast(&src_addr));
        std.debug.print("Recebido de {}: {s}\n", .{ sender, buffer[0..bytes_received] });

        // Enviar resposta de volta ao remetente
        const response = "ACK";
        _ = try posix.sendto(
            sock,
            response,
            0,
            &src_addr,
            addr_len,
        );
    }
}
```

## Cliente UDP Básico

O cliente envia datagramas ao servidor e recebe respostas:

```zig
const std = @import("std");
const net = std.net;
const posix = std.posix;

pub fn main() !void {
    // Criar socket UDP
    const sock = try posix.socket(posix.AF.INET, posix.SOCK.DGRAM, 0);
    defer posix.close(sock);

    // Endereço do servidor
    const server_addr = net.Address.initIp4(.{ 127, 0, 0, 1 }, 9000);

    // Enviar datagrama
    const message = "Olá, servidor UDP!";
    _ = try posix.sendto(
        sock,
        message,
        0,
        &server_addr.any,
        server_addr.getOsSockLen(),
    );
    std.debug.print("Enviado: {s}\n", .{message});

    // Receber resposta
    var buffer: [1024]u8 = undefined;
    var src_addr: posix.sockaddr = undefined;
    var addr_len: posix.socklen_t = @sizeOf(posix.sockaddr);

    const bytes_received = try posix.recvfrom(
        sock,
        &buffer,
        0,
        &src_addr,
        &addr_len,
    );

    std.debug.print("Resposta: {s}\n", .{buffer[0..bytes_received]});
}
```

### Saída esperada

Cliente:
```
Enviado: Olá, servidor UDP!
Resposta: ACK
```

Servidor:
```
Servidor UDP escutando na porta 9000...
Recebido de 127.0.0.1:45678: Olá, servidor UDP!
```

## UDP Multicast

Multicast permite enviar dados para múltiplos receptores simultaneamente:

```zig
const std = @import("std");
const net = std.net;
const posix = std.posix;

/// Receptor multicast
pub fn multicastReceiver() !void {
    const sock = try posix.socket(posix.AF.INET, posix.SOCK.DGRAM, 0);
    defer posix.close(sock);

    // Permitir reutilização do endereço
    try posix.setsockopt(sock, posix.SOL.SOCKET, posix.SO.REUSEADDR, &std.mem.toBytes(@as(c_int, 1)));

    // Vincular à porta multicast
    const bind_addr = net.Address.initIp4(.{ 0, 0, 0, 0 }, 5000);
    try posix.bind(sock, &bind_addr.any, bind_addr.getOsSockLen());

    // Entrar no grupo multicast 239.0.0.1
    const mreq = extern struct {
        multiaddr: [4]u8,
        interface: [4]u8,
    }{
        .multiaddr = .{ 239, 0, 0, 1 },
        .interface = .{ 0, 0, 0, 0 },
    };

    try posix.setsockopt(sock, posix.IPPROTO.IP, 12, // IP_ADD_MEMBERSHIP
        std.mem.asBytes(&mreq));

    std.debug.print("Escutando multicast em 239.0.0.1:5000...\n", .{});

    var buffer: [1024]u8 = undefined;
    while (true) {
        var src_addr: posix.sockaddr = undefined;
        var addr_len: posix.socklen_t = @sizeOf(posix.sockaddr);

        const n = try posix.recvfrom(sock, &buffer, 0, &src_addr, &addr_len);
        std.debug.print("Multicast: {s}\n", .{buffer[0..n]});
    }
}

/// Emissor multicast
pub fn multicastSender() !void {
    const sock = try posix.socket(posix.AF.INET, posix.SOCK.DGRAM, 0);
    defer posix.close(sock);

    const dest = net.Address.initIp4(.{ 239, 0, 0, 1 }, 5000);

    const message = "Broadcast para todos!";
    _ = try posix.sendto(
        sock,
        message,
        0,
        &dest.any,
        dest.getOsSockLen(),
    );
    std.debug.print("Mensagem multicast enviada.\n", .{});
}
```

## UDP com Timeout

Adicione timeouts para evitar bloqueio indefinido ao esperar respostas:

```zig
const std = @import("std");
const net = std.net;
const posix = std.posix;

pub fn udpWithTimeout() !void {
    const sock = try posix.socket(posix.AF.INET, posix.SOCK.DGRAM, 0);
    defer posix.close(sock);

    // Configurar timeout de 3 segundos
    const timeout = posix.timeval{
        .sec = 3,
        .usec = 0,
    };
    try posix.setsockopt(
        sock,
        posix.SOL.SOCKET,
        posix.SO.RCVTIMEO,
        &std.mem.toBytes(timeout),
    );

    const server = net.Address.initIp4(.{ 127, 0, 0, 1 }, 9000);
    _ = try posix.sendto(sock, "ping", 0, &server.any, server.getOsSockLen());

    var buffer: [1024]u8 = undefined;
    var src_addr: posix.sockaddr = undefined;
    var addr_len: posix.socklen_t = @sizeOf(posix.sockaddr);

    _ = posix.recvfrom(sock, &buffer, 0, &src_addr, &addr_len) catch |err| {
        if (err == error.WouldBlock) {
            std.debug.print("Timeout: nenhuma resposta em 3 segundos.\n", .{});
            return;
        }
        return err;
    };
}
```

## TCP vs UDP: Quando Usar Cada Um

| Característica | TCP | UDP |
|---|---|---|
| Conexão | Orientado a conexão | Sem conexão |
| Confiabilidade | Entrega garantida | Sem garantia |
| Ordem | Ordenado | Não ordenado |
| Overhead | Maior | Menor |
| Uso ideal | HTTP, FTP, e-mail | Jogos, DNS, streaming |

## Dicas e Boas Práticas

1. **Tamanho máximo do datagrama**: O tamanho máximo prático de um datagrama UDP é 65.507 bytes, mas para evitar fragmentação IP, mantenha abaixo de 1.472 bytes (1.500 MTU - headers).

2. **UDP não é confiável**: Datagramas podem ser perdidos, duplicados ou chegar fora de ordem. Implemente confirmação (ACK) se necessário.

3. **Use timeouts**: Sempre configure timeouts ao esperar respostas UDP.

4. **Gerencie memória**: Use [allocators do Zig](/tutoriais/gerenciamento-de-memoria-zig/) adequadamente para buffers dinâmicos.

## Receitas Relacionadas

- [Como criar um cliente TCP em Zig](/receitas/zig-tcp-client/) - Alternativa confiável com TCP
- [Como criar um servidor TCP em Zig](/receitas/zig-tcp-server/) - Servidor TCP
- [Como fazer lookup DNS em Zig](/receitas/zig-dns-lookup/) - DNS usa UDP
- [Como tratar erros em Zig](/receitas/zig-try-catch-erros/) - Tratamento de erros de rede

## Tutoriais Relacionados

- [Networking e Sockets em Zig](/tutoriais/zig-networking-sockets/)
- [Introdução ao Zig](/tutoriais/introducao-ao-zig/)
