---
title: "Como Criar um Cliente TCP em Zig"
url: "https://ziglang.com.br/receitas/como-criar-um-cliente-tcp-em-zig/"
markdown_url: "https://ziglang.com.br/receitas/como-criar-um-cliente-tcp-em-zig.MD"
description: "Aprenda a criar um cliente TCP em Zig para conectar-se a servidores remotos, enviar dados e receber respostas usando a biblioteca padrão de rede."
date: "2026-02-21"
author: "Zig Brasil"
---

# Como Criar um Cliente TCP em Zig

Aprenda a criar um cliente TCP em Zig para conectar-se a servidores remotos, enviar dados e receber respostas usando a biblioteca padrão de rede.


## Introdução

Um cliente TCP é um programa que inicia uma conexão com um servidor remoto usando o protocolo TCP (Transmission Control Protocol). TCP garante a entrega ordenada e confiável de dados, sendo essencial para aplicações como navegadores web, clientes de e-mail e ferramentas de linha de comando.

Nesta receita, você aprenderá a criar um cliente TCP funcional em Zig usando a biblioteca padrão `std.net`. Veremos como estabelecer conexões, enviar requisições e processar respostas.

## 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/)
- Familiaridade com conceitos de rede

## Cliente TCP Básico

O exemplo a seguir conecta-se a um servidor, envia uma mensagem e lê a resposta:

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

pub fn main() !void {
    // Conectar ao servidor na porta 8080
    const address = net.Address.initIp4(.{ 127, 0, 0, 1 }, 8080);
    const stream = try net.tcpConnectToAddress(address);
    defer stream.close();

    // Enviar dados ao servidor
    const message = "Olá, servidor!";
    _ = try stream.write(message);

    // Ler resposta do servidor
    var buffer: [1024]u8 = undefined;
    const bytes_read = try stream.read(&buffer);

    if (bytes_read > 0) {
        const response = buffer[0..bytes_read];
        std.debug.print("Resposta do servidor: {s}\n", .{response});
    } else {
        std.debug.print("Servidor fechou a conexão sem responder.\n", .{});
    }
}
```

### Saída esperada

```
Resposta do servidor: Mensagem recebida com sucesso!
```

## Conectando por Nome de Host

Na maioria dos casos reais, você se conecta por nome de host em vez de endereço IP direto. Use `net.tcpConnectToHost` para resolução DNS automática:

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

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

    // Conectar por nome de host (resolução DNS automática)
    const stream = try net.tcpConnectToHost(allocator, "example.com", 80);
    defer stream.close();

    // Enviar uma 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);

    // Ler toda a resposta
    var response_buf = std.ArrayList(u8).init(allocator);
    defer response_buf.deinit();

    var buffer: [4096]u8 = undefined;
    while (true) {
        const bytes_read = try stream.read(&buffer);
        if (bytes_read == 0) break;
        try response_buf.appendSlice(buffer[0..bytes_read]);
    }

    std.debug.print("Resposta ({d} bytes):\n{s}\n", .{
        response_buf.items.len,
        response_buf.items,
    });
}
```

## Cliente TCP com Timeout

Em aplicações de produção, é importante configurar timeouts para evitar que o programa fique bloqueado indefinidamente:

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

pub fn main() !void {
    const address = net.Address.initIp4(.{ 127, 0, 0, 1 }, 8080);
    const stream = try net.tcpConnectToAddress(address);
    defer stream.close();

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

    // Configurar timeout de escrita (5 segundos)
    try posix.setsockopt(
        stream.handle,
        posix.SOL.SOCKET,
        posix.SO.SNDTIMEO,
        &std.mem.toBytes(timeout),
    );

    _ = try stream.write("Dados com timeout");

    var buffer: [1024]u8 = undefined;
    const bytes_read = stream.read(&buffer) catch |err| {
        if (err == error.WouldBlock) {
            std.debug.print("Timeout: servidor não respondeu em 5 segundos.\n", .{});
            return;
        }
        return err;
    };

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

## Cliente TCP com Reconexão Automática

Para aplicações que precisam manter conexões persistentes, implemente um mecanismo de reconexão:

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

const TcpClient = struct {
    address: net.Address,
    stream: ?net.Stream,
    max_retries: u32,

    pub fn init(ip: [4]u8, port: u16, max_retries: u32) TcpClient {
        return .{
            .address = net.Address.initIp4(ip, port),
            .stream = null,
            .max_retries = max_retries,
        };
    }

    pub fn connect(self: *TcpClient) !void {
        var attempt: u32 = 0;
        while (attempt < self.max_retries) : (attempt += 1) {
            self.stream = net.tcpConnectToAddress(self.address) catch |err| {
                std.debug.print(
                    "Tentativa {d}/{d} falhou: {}\n",
                    .{ attempt + 1, self.max_retries, err },
                );
                std.time.sleep(std.time.ns_per_s * (attempt + 1));
                continue;
            };
            std.debug.print("Conectado com sucesso na tentativa {d}!\n", .{attempt + 1});
            return;
        }
        return error.ConnectionFailed;
    }

    pub fn send(self: *TcpClient, data: []const u8) !usize {
        if (self.stream) |stream| {
            return stream.write(data);
        }
        return error.NotConnected;
    }

    pub fn receive(self: *TcpClient, buffer: []u8) !usize {
        if (self.stream) |stream| {
            return stream.read(buffer);
        }
        return error.NotConnected;
    }

    pub fn close(self: *TcpClient) void {
        if (self.stream) |stream| {
            stream.close();
            self.stream = null;
        }
    }
};

pub fn main() !void {
    var client = TcpClient.init(.{ 127, 0, 0, 1 }, 8080, 3);
    defer client.close();

    try client.connect();

    _ = try client.send("Olá com reconexão!");

    var buffer: [1024]u8 = undefined;
    const n = try client.receive(&buffer);
    std.debug.print("Recebido: {s}\n", .{buffer[0..n]});
}
```

## Dicas e Boas Práticas

1. **Sempre feche conexões**: Use `defer stream.close()` para garantir que a conexão seja fechada mesmo em caso de erro.

2. **Trate erros de rede**: Conexões podem falhar por diversos motivos. Utilize o [tratamento de erros do Zig](/tutoriais/tratamento-de-erros-em-zig/) adequadamente.

3. **Use buffers adequados**: Dimensione seus buffers de acordo com o tamanho esperado dos dados. Para dados grandes, leia em loop.

4. **Configure timeouts**: Em produção, sempre configure timeouts para evitar bloqueios indefinidos.

5. **Gerencie memória corretamente**: Use o [gerenciamento de memória do Zig](/tutoriais/gerenciamento-de-memoria-zig/) com allocators apropriados.

## Receitas Relacionadas

- [Como criar um servidor TCP em Zig](/receitas/zig-tcp-server/) - O complemento desta receita
- [Como usar sockets UDP em Zig](/receitas/zig-udp-socket/) - Alternativa com UDP
- [Como fazer requisições HTTP GET em Zig](/receitas/zig-http-get-request/) - HTTP sobre TCP
- [Como fazer lookup DNS em Zig](/receitas/zig-dns-lookup/) - Resolução de nomes

## Tutoriais Relacionados

- [Networking e Sockets em Zig](/tutoriais/zig-networking-sockets/)
- [Tratamento de Erros em Zig](/tutoriais/tratamento-de-erros-em-zig/)
- [Gerenciamento de Memória em Zig](/tutoriais/gerenciamento-de-memoria-zig/)
