# 📖 Guia Completo do FastNet
> Networking UDP encriptado de ultra-baixa latência para jogos em tempo real e aplicações de rede.
---
## Índice
1. [Visão Geral](#1-visão-geral)
2. [Instalação](#2-instalação)
3. [Conceitos Fundamentais](#3-conceitos-fundamentais)
4. [Criando um Servidor](#4-criando-um-servidor)
5. [Criando um Cliente](#5-criando-um-cliente)
6. [Canais de Comunicação](#6-canais-de-comunicação)
7. [Enviando e Recebendo Dados](#7-enviando-e-recebendo-dados)
8. [Desconexão e Detecção de Crash](#8-desconexão-e-detecção-de-crash)
9. [Certificados TLS](#9-certificados-tls)
10. [Integração C/C++ (FFI)](#10-integração-cc-ffi)
11. [Rede P2P](#11-rede-p2p)
12. [Fallback TCP](#12-fallback-tcp)
13. [Transferência de Assets](#13-transferência-de-assets)
14. [Módulos Avançados](#14-módulos-avançados)
- [BBR Congestion Control](#bbr-congestion-control)
- [FEC (Forward Error Correction)](#fec-forward-error-correction)
- [Delta Compression](#delta-compression)
- [Priority Queues](#priority-queues)
- [Jitter Buffer](#jitter-buffer)
- [Métricas](#métricas)
- [Reconexão 0-RTT](#reconexão-0-rtt)
- [Migração de Conexão](#migração-de-conexão)
- [Interest Management](#interest-management)
15. [Tuning de Performance](#15-tuning-de-performance)
16. [Exemplos Prontos](#16-exemplos-prontos)
17. [Perguntas Frequentes](#17-perguntas-frequentes)
---
## 1. Visão Geral
O **FastNet** é uma biblioteca de networking de alta performance projetada para jogos multiplayer em tempo real, mas que se adapta perfeitamente a qualquer aplicação que precise de comunicação UDP encriptada com baixa latência.
### Características Principais
- **Ultra-baixa latência**: ~14µs de RTT mediana em localhost (2.7x mais rápido que QUIC)
- **Encriptação nativa**: TLS 1.3 handshake + ChaCha20-Poly1305 AEAD
- **Zero alocações no hot path**: encriptação/decriptação in-place
- **4 tipos de canal**: Unreliable, UnreliableSequenced, Reliable, ReliableOrdered
- **Detecção de crash**: timeout automático para peers que caem sem aviso
- **Async/Await**: construído sobre Tokio
### Como Funciona
```
Cliente Servidor
│ │
│──────── TCP TLS 1.3 ──────────▶│ (Troca de chaves, ~40ms)
│◀─────── Chaves de Sessão ──────│
│ │
│════════ UDP Encriptado ════════▶│ (Dados do jogo, ~15µs)
│◀═══════ UDP Encriptado ═════════│
```
1. O cliente conecta via **TCP** para realizar o handshake TLS 1.3
2. O servidor gera chaves ChaCha20 únicas para cada cliente
3. Todos os dados UDP são encriptados com AEAD (autenticação + encriptação)
4. Cada pacote inclui tag de autenticação contra adulteração
---
## 2. Instalação
### Dependências no `Cargo.toml`
```toml
[dependencies]
fastnet = "0.3"
tokio = { version = "1", features = ["rt-multi-thread", "net", "time", "macros", "sync"] }
```
Para desenvolvimento com certificados auto-assinados, adicione a feature `dev-certs`:
```toml
[dependencies]
fastnet = { version = "0.3", features = ["dev-certs"] }
rcgen = "0.13" # Gerar certificados em runtime
rustls = "0.23" # Para tipos de certificado
tokio = { version = "1", features = ["rt-multi-thread", "net", "time", "macros", "sync"] }
```
Para compilar a biblioteca para C/C++:
```toml
fastnet = { version = "0.3", features = ["ffi"] }
```
---
## 3. Conceitos Fundamentais
### SecureSocket
O `SecureSocket` é a API principal do FastNet. Ele gerencia:
- Conexões encriptadas via UDP
- Handshake TLS 1.3 para troca segura de chaves
- Envio e recebimento de dados em múltiplos canais
- Detecção de desconexão (graceful e por timeout)
### SecureEvent
Eventos retornados pelo método `poll()`:
```rust
enum SecureEvent {
Connected(u16), // Um peer conectou. O u16 é o peer_id.
Data(u16, u8, Vec<u8>), // Dados recebidos: (peer_id, canal, dados)
Disconnected(u16), // Um peer desconectou. O u16 é o peer_id.
}
```
### PeerId
Cada conexão recebe um identificador único do tipo `u16`. Use esse ID para enviar dados e gerenciar peers.
### Canais
Os canais determinam como os pacotes são entregues. Cada `SecureSocket` tem 4 canais por padrão:
| `0` | ReliableOrdered | ✅ | ✅ | Chat, comandos, eventos críticos |
| `1` | Unreliable | ❌ | ❌ | Posição de jogadores, partículas |
| `2` | Reliable | ✅ | ❌ | Pickups, eventos de dano |
| `3` | UnreliableSequenced | ❌ | Último | Input, voz |
---
## 4. Criando um Servidor
### Com Certificados de Desenvolvimento
```rust
use std::net::SocketAddr;
use fastnet::{SecureSocket, SecureEvent};
use rcgen::generate_simple_self_signed;
use rustls::pki_types::PrivateKeyDer;
#[tokio::main]
async fn main() -> std::io::Result<()> {
// Gerar certificado auto-assinado (apenas para desenvolvimento!)
let cert = generate_simple_self_signed(vec!["localhost".into()])
.expect("Falha ao gerar certificado");
let certs = vec![cert.cert.der().clone()];
let key = PrivateKeyDer::Pkcs8(cert.key_pair.serialize_der().into());
// Endereços: UDP para dados, TCP para handshake TLS
let udp_addr: SocketAddr = "0.0.0.0:7777".parse().unwrap();
let tcp_addr: SocketAddr = "0.0.0.0:7778".parse().unwrap();
// Criar o socket do servidor
let mut server = SecureSocket::bind_server(udp_addr, tcp_addr, certs, key).await?;
println!("Servidor rodando em UDP:{} TCP:{}", udp_addr, tcp_addr);
// Loop principal
loop {
// poll() retorna os eventos desde a última chamada
for event in server.poll().await? {
match event {
SecureEvent::Connected(peer_id) => {
println!("Peer {} conectou", peer_id);
}
SecureEvent::Data(peer_id, channel, data) => {
println!("Recebido de {}: {} bytes no canal {}",
peer_id, data.len(), channel);
// Exemplo: echo de volta
server.send(peer_id, channel, data).await?;
}
SecureEvent::Disconnected(peer_id) => {
println!("Peer {} desconectou", peer_id);
}
}
}
}
}
```
### Pontos Importantes
- **`bind_server`** precisa de dois endereços: um UDP (dados) e um TCP (handshake)
- **`poll()`** é assíncrono e retorna eventos acumulados
- Se não houver eventos, `poll()` aguarda até receber um pacote ou até o timeout interno de 1 segundo
- O servidor aceita múltiplas conexões simultâneas
- Use `server.peer_count()` para saber quantos peers estão conectados
---
## 5. Criando um Cliente
```rust
use std::time::Duration;
use fastnet::{SecureSocket, SecureEvent};
#[tokio::main]
async fn main() -> std::io::Result<()> {
// Conectar ao servidor (endereço TCP para handshake)
let server_addr = "127.0.0.1:7778".parse().unwrap();
let mut client = SecureSocket::connect(server_addr).await?;
// Aguardar o evento Connected para obter o peer_id
let peer_id = loop {
for event in client.poll().await? {
if let SecureEvent::Connected(id) = event {
println!("Conectado! Meu peer_id: {}", id);
break id; // Este é o ID do servidor no lado do cliente
}
}
// Se não recebeu ainda, continue tentando
break 1; // fallback
};
// Enviar dados no canal 0 (ReliableOrdered)
client.send(peer_id, 0, b"Olá, servidor!".to_vec()).await?;
// Receber resposta
for event in client.poll().await? {
if let SecureEvent::Data(_, _, data) = event {
println!("Resposta: {}", String::from_utf8_lossy(&data));
}
}
// Desconectar graciosamente
client.disconnect(peer_id).await?;
Ok(())
}
```
### Pontos Importantes
- **`connect()`** recebe o endereço **TCP** do servidor (não o UDP)
- O handshake TLS é feito automaticamente durante o `connect()`
- O `peer_id` retornado no `Connected` é o ID que você usa para `send()` e `disconnect()`
- Sempre chame `disconnect()` antes de encerrar para notificar o outro lado
---
## 6. Canais de Comunicação
### Canal 0 — ReliableOrdered (Confiável e Ordenado)
**Quando usar:** Mensagens de chat, comandos, sincronização de estado crítico.
```rust
// Garantia: entrega na ordem exata, sem perdas
client.send(peer_id, 0, b"mensagem importante".to_vec()).await?;
```
- ✅ Pacotes são retransmitidos se perdidos
- ✅ Chegam na ordem exata que foram enviados
- ⚠️ Um pacote perdido bloqueia os seguintes até ser retransmitido
- 📊 Maior latência que canais unreliable
### Canal 1 — Unreliable (Não Confiável)
**Quando usar:** Posições de jogadores, efeitos visuais, partículas.
```rust
// Sem garantias — rápido mas pode perder pacotes
client.send(peer_id, 1, position_bytes.to_vec()).await?;
```
- ❌ Pacotes podem ser perdidos (UDP puro)
- ❌ Podem chegar fora de ordem
- ✅ Menor latência possível
- ✅ Não bloqueia outros pacotes
- 📊 Ideal para dados que são substituídos a cada frame
### Canal 2 — Reliable (Confiável, Sem Ordem)
**Quando usar:** Pickups de itens, eventos de dano, notificações.
```rust
// Garantia de entrega, mas pode chegar em qualquer ordem
client.send(peer_id, 2, b"item_coletado:espada".to_vec()).await?;
```
- ✅ Pacotes são retransmitidos se perdidos
- ❌ Podem chegar fora de ordem
- ✅ Não bloqueia outros pacotes (diferente do ReliableOrdered)
- 📊 Bom para eventos importantes que não dependem de sequência
### Canal 3 — UnreliableSequenced (Não Confiável, Sequenciado)
**Quando usar:** Input do jogador, streaming de voz, estado de animação.
```rust
// Apenas o pacote mais recente é processado
client.send(peer_id, 3, input_state.to_vec()).await?;
```
- ❌ Pacotes podem ser perdidos
- ✅ Pacotes antigos são descartados automaticamente
- ✅ Sempre recebe apenas o dado mais recente
- 📊 Perfeito para dados onde só o último valor importa
### Resumo Visual
```
Reliable Ordered (canal 0): [1] [2] [3] [4] → recebe [1] [2] [3] [4] ✓ ordem
Unreliable (canal 1): [1] [2] [X] [4] → recebe [1] [4] [2] qualquer ordem
Reliable (canal 2): [1] [X] [3] [4] → recebe [3] [1] [4] ✓ entrega, ? ordem
Unreliable Sequenced (canal 3):[1] [2] [X] [4] → recebe [4] apenas o último
```
---
## 7. Enviando e Recebendo Dados
### Envio Básico
```rust
// send(peer_id, canal, dados) -> Result<()>
socket.send(peer_id, 0, b"texto simples".to_vec()).await?;
```
### Enviando Dados Binários Estruturados
```rust
// Criar um pacote binário manualmente
fn build_position_packet(x: f32, y: f32, z: f32) -> Vec<u8> {
let mut buf = Vec::with_capacity(12);
buf.extend_from_slice(&x.to_le_bytes());
buf.extend_from_slice(&y.to_le_bytes());
buf.extend_from_slice(&z.to_le_bytes());
buf
}
// Enviar posição no canal 1 (unreliable — alta frequência)
let pos = build_position_packet(10.5, 20.0, -5.3);
socket.send(peer_id, 1, pos).await?;
```
### Recebendo e Parseando Dados
```rust
for event in socket.poll().await? {
match event {
SecureEvent::Data(peer_id, channel, data) => {
match channel {
0 => {
// Canal 0: mensagens de texto (ReliableOrdered)
let msg = String::from_utf8_lossy(&data);
println!("[{}] {}", peer_id, msg);
}
1 => {
// Canal 1: posição (Unreliable)
if data.len() >= 12 {
let x = f32::from_le_bytes(data[0..4].try_into().unwrap());
let y = f32::from_le_bytes(data[4..8].try_into().unwrap());
let z = f32::from_le_bytes(data[8..12].try_into().unwrap());
println!("Peer {} em ({}, {}, {})", peer_id, x, y, z);
}
}
_ => {}
}
}
_ => {}
}
}
```
### Protocolo com Prefixo de Tipo
Uma prática comum é usar o primeiro byte para identificar o tipo da mensagem:
```rust
const MSG_CHAT: u8 = 0x01;
const MSG_POSITION: u8 = 0x02;
const MSG_ACTION: u8 = 0x03;
// Enviar
fn send_chat(socket: &mut SecureSocket, peer: u16, text: &str) {
let mut buf = vec![MSG_CHAT];
buf.extend_from_slice(text.as_bytes());
socket.send(peer, 0, buf); // Chat no canal reliable
}
// Receber
match data[0] {
MSG_CHAT => {
let text = String::from_utf8_lossy(&data[1..]);
println!("Chat: {}", text);
}
MSG_POSITION => { /* parsear posição */ }
MSG_ACTION => { /* parsear ação */ }
_ => {}
}
```
### Broadcast para Múltiplos Peers
O FastNet não tem broadcast nativo — você envia para cada peer individualmente:
```rust
// Coletar as mensagens primeiro para evitar conflito de empréstimo
let mut messages: Vec<(u16, Vec<u8>)> = Vec::new();
for &peer_id in &connected_peers {
messages.push((peer_id, data.clone()));
}
// Depois enviar
for (peer_id, data) in messages {
let _ = server.send(peer_id, channel, data).await;
}
```
---
## 8. Desconexão e Detecção de Crash
### Desconexão Graciosa
```rust
// O lado que quer desconectar chama:
socket.disconnect(peer_id).await?;
// O outro lado recebe:
SecureEvent::Disconnected(peer_id)
```
O `disconnect()` envia **3 pacotes UDP** de desconexão para garantir que o outro lado receba (UDP pode perder pacotes).
### Detecção de Crash (Timeout)
Se um peer crashar sem enviar pacote de disconnect, o outro lado detecta via **timeout**:
- **Timeout padrão**: 10 segundos
- O `poll()` verifica automaticamente se algum peer parou de responder
- Quando o timeout expira, um `SecureEvent::Disconnected` é gerado
```rust
// O servidor detecta client crashado:
SecureEvent::Disconnected(peer_id) // Após ~10 segundos sem resposta
// O cliente detecta server crashado:
SecureEvent::Disconnected(peer_id) // Após ~10 segundos sem resposta
```
### Cenários de Desconexão
| Client chama `disconnect()` | Server recebe pacote Disconnect | Instantâneo |
| Server chama `disconnect()` | Client recebe pacote Disconnect | Instantâneo |
| Client crasha (kill, crash, rede cai) | Server detecta via timeout | ~10s |
| Server crasha (kill, crash, rede cai) | Client detecta via timeout | ~10s |
### Verificando Peers Conectados
```rust
let count = socket.peer_count();
println!("{} peers conectados", count);
```
---
## 9. Certificados TLS
### Desenvolvimento (Auto-assinados)
Para testes e desenvolvimento, use a feature `dev-certs` com `rcgen`:
```rust
use rcgen::generate_simple_self_signed;
use rustls::pki_types::PrivateKeyDer;
let cert = generate_simple_self_signed(vec!["localhost".into()])
.expect("Falha ao gerar certificado");
let certs = vec![cert.cert.der().clone()];
let key = PrivateKeyDer::Pkcs8(cert.key_pair.serialize_der().into());
let server = SecureSocket::bind_server(udp_addr, tcp_addr, certs, key).await?;
```
### Produção (Certificados Reais)
Para produção, use certificados do Let's Encrypt ou de uma CA:
```bash
# Gerar certificado auto-assinado com OpenSSL (válido por 365 dias)
openssl req -x509 -newkey rsa:4096 \
-keyout key.pem -out cert.pem \
-days 365 -nodes \
-subj "/CN=seu-dominio.com"
```
Carregar no código:
```rust
use std::fs::File;
use std::io::BufReader;
use rustls_pemfile;
let cert_file = File::open("cert.pem")?;
let key_file = File::open("key.pem")?;
let certs = rustls_pemfile::certs(&mut BufReader::new(cert_file))
.collect::<Result<Vec<_>, _>>()?;
let key = rustls_pemfile::private_key(&mut BufReader::new(key_file))?
.expect("Nenhuma chave privada encontrada");
```
> **Nota:** O cliente FastNet usa verificação de certificado desabilitada por padrão (`InsecureVerifier`) para facilitar o desenvolvimento. Em produção, implemente verificação de certificado adequada.
---
## 10. Integração C/C++ (FFI)
Compile com a feature `ffi`:
```bash
cargo build --release --features ffi
```
Isso gera:
- Linux: `target/release/libfastnet.so`
- Windows: `target/release/fastnet.dll`
- macOS: `target/release/libfastnet.dylib`
### Exemplo em C
```c
#include "fastnet.h"
int main() {
FastNetClient client = fastnet_client_connect("127.0.0.1", 7778);
if (!client) return 1;
uint8_t data[] = {1, 2, 3, 4};
fastnet_client_send(client, 0, data, sizeof(data));
FastNetEvent event;
while (fastnet_client_poll(client, &event)) {
switch (event.type) {
case FASTNET_EVENT_CONNECTED:
printf("Conectado como peer %d\n", event.peer_id);
break;
case FASTNET_EVENT_DATA:
printf("Recebido %d bytes\n", event.data_len);
break;
case FASTNET_EVENT_DISCONNECTED:
printf("Desconectado\n");
break;
}
}
fastnet_client_disconnect(client);
return 0;
}
```
### Unreal Engine
1. Copie a `.dll`/`.so` para `YourProject/Binaries/`
2. Inclua o header `fastnet.h`
3. Use no seu `GameInstance`:
```cpp
#include "FastNet.h"
void UMyGameInstance::Init() {
NetworkClient = MakeUnique<FFastNetClient>();
NetworkClient->Connect("127.0.0.1", 7778);
}
void UMyGameInstance::Tick(float DeltaTime) {
FFastNetEvent Event;
while (NetworkClient->Poll(Event)) {
if (Event.Type == EFastNetEventType::Data)
ProcessNetworkData(Event.Data);
}
}
```
---
## 11. Rede P2P
Conexão direta entre peers com NAT traversal:
```rust
use fastnet::p2p::{P2PSocket, P2PEvent};
let mut socket = P2PSocket::connect("signaling.example.com:9000").await?;
socket.join_room("sala-123").await?;
loop {
for event in socket.poll().await? {
match event {
P2PEvent::PeerConnected(peer_id) => {
println!("Conexão direta com peer {}", peer_id);
socket.send(peer_id, b"Olá!".to_vec()).await?;
}
P2PEvent::Data(peer_id, data) => {
println!("De {}: {:?}", peer_id, data);
}
P2PEvent::PeerRelayed(peer_id) => {
println!("Peer {} usando relay (NAT traversal falhou)", peer_id);
}
_ => {}
}
}
}
```
**Recursos:**
- UDP hole-punching para NAT traversal
- Fallback automático para relay
- Descoberta de peers por salas
- Encriptação ponta-a-ponta (ChaCha20-Poly1305)
---
## 12. Fallback TCP
Fallback automático para TCP quando UDP está bloqueado:
```rust
use fastnet::tcp::{HybridSocket, TransportMode};
let mut socket = HybridSocket::connect("game.example.com:7778").await?;
match socket.transport_mode() {
TransportMode::Udp => println!("Usando UDP (ótimo!)"),
TransportMode::Tcp => println!("Usando TCP (fallback)"),
}
// A API é idêntica independente do transporte
socket.send(1, 0, b"Olá!".to_vec()).await?;
```
---
## 13. Transferência de Assets
Transferência eficiente de arquivos grandes com compressão e verificação:
```rust
use fastnet::assets::{AssetServer, AssetClient, AssetEvent};
// Servidor: registrar e servir assets
let mut server = AssetServer::new(Default::default());
server.register("mapa.pak", "/game/maps/floresta.pak").await?;
// Cliente: baixar assets
let mut client = AssetClient::new();
client.start_download(transfer_id, info, "/local/maps/floresta.pak")?;
for event in client.poll_events() {
match event {
AssetEvent::Progress { received, total, .. } => {
let pct = (received as f64 / total as f64) * 100.0;
println!("Download: {:.1}%", pct);
}
AssetEvent::Completed { path, .. } => {
println!("Baixado: {:?}", path);
}
_ => {}
}
}
```
**Recursos:**
- Chunks de 64KB
- Compressão LZ4
- Verificação BLAKE3 (por chunk e por arquivo)
- Downloads resumíveis
- Pause/cancel
---
## 14. Módulos Avançados
### BBR Congestion Control
Algoritmo de controle de congestionamento do Google. Em vez de cortar a velocidade pela metade quando um pacote é perdido (como TCP), o BBR estima a largura de banda e o RTT mínimo continuamente:
```
TCP Tradicional (AIMD):
↗ Aumenta velocidade lentamente
↘ Pacote perdido? Corta pela metade!
Resultado: padrão dente-de-serra, desperdício de 50%
BBR (FastNet):
📊 Estima continuamente: largura de banda + RTT mínimo
🎯 Envia na taxa ótima exata
📉 Pacote perdido? Sem pânico — mantém taxa estável
Resultado: 2.3x mais throughput sob 5% de perda!
```
### FEC (Forward Error Correction)
Recupera pacotes perdidos sem esperar retransmissão:
```
Envio: [Pkt1] [Pkt2] [Pkt3] [Paridade]
Perdido: [Pkt1] [ X ] [Pkt3] [Paridade]
Recupera: Pkt2 = Pkt1 XOR Pkt3 XOR Paridade ✓
```
Economiza 1 RTT (~30ms) em caso de perda — crítico para jogos rápidos.
### Delta Compression
Envia apenas o que mudou entre frames:
```
Frame 1: {x: 100, y: 200, health: 100, ammo: 30, ...} → 500 bytes
Frame 2: {x: 101, y: 200, health: 100, ammo: 30, ...} → apenas x mudou!
Sem Delta: enviar 500 bytes
Com Delta: enviar {offset: 0, valor: 101} → 8 bytes (98% menor!)
```
**Economia típica: 80-95% de redução de banda** para atualizações de estado.
### Priority Queues
Quando a banda é limitada, pacotes importantes têm prioridade:
```
[CRITICAL] Morte do jogador, hit detection → sempre enviado
[HIGH] Atualizações de posição → enviado em seguida
[NORMAL] Animações → enviado se banda permitir
[LOW] Efeitos cosméticos → enviado quando possível
```
### Jitter Buffer
Suaviza variações de timing na rede para voz/vídeo:
```
Pacotes chegam: [1]...[2][3]...[4][5][6] (timing variável)
Jitter Buffer: [1][2][3][4][5][6] (timing constante)
```
### Métricas
Monitoramento em tempo real de:
- RTT (média, mínimo, máximo)
- Jitter
- Throughput (envio e recebimento)
- Perda de pacotes
- Retransmissões
### Reconexão 0-RTT
Reconexão instantânea após mudança de rede:
```
Conexão normal: Client → "Olá" → Server → "Olá" → pronto (1 RTT)
0-RTT: Client → "Tenho ticket" + dados → pronto instantâneo!
```
### Migração de Conexão
Handoff transparente quando o IP muda (WiFi → 4G):
```
Jogador no WiFi: IP 192.168.1.50
Troca para 4G: IP 189.45.23.100
Sem Migração: desconectado, perde progresso
Com Migração: client prova identidade com HMAC, continua jogando
```
### Interest Management
Para MMOs — envia atualizações apenas sobre entidades próximas:
```
Mundo do Jogo:
┌─────────────────────────────┐
│ [A] [B] │ A, B, C = longe
│ [Você] │
│ [C] │ D, E = perto
│ [D] [E] │
└─────────────────────────────┘
Sem Interest: recebe updates de A,B,C,D,E (5 jogadores)
Com Interest: recebe apenas D,E (próximos) → 60% menos banda
```
---
## 15. Tuning de Performance
### Configuração de Socket
```rust
use fastnet::net::fast::SocketConfig;
// Configuração de baixa latência
let config = SocketConfig::low_latency();
// - SO_RCVBUF/SO_SNDBUF: 8MB
// - SO_BUSY_POLL: 100µs
// - IP_TOS: 0xB8 (DSCP EF)
// - SO_PRIORITY: 6
```
### Otimizações Linux
| `SO_RCVBUF` / `SO_SNDBUF` | Buffers de 4-8MB para evitar drops |
| `SO_BUSY_POLL` | CPU polling — reduz latência em ~10µs |
| `IP_TOS` | DSCP EF (Expedited Forwarding) para QoS em routers |
| `sendmmsg` / `recvmmsg` | Enviar/receber múltiplos pacotes por syscall |
### Dicas de Performance
1. **Use o canal correto**: Não use ReliableOrdered para tudo — isso causa head-of-line blocking
2. **Posições no canal Unreliable**: Posições são substituídas a cada frame, não precisa garantia
3. **Input no canal Sequenced**: Apenas o input mais recente importa
4. **Eventos críticos no canal Reliable**: Pickups, dano, etc.
5. **Chat no canal ReliableOrdered**: Mensagens precisam chegar em ordem
---
## 16. Exemplos Prontos
O FastNet vem com exemplos completos (server + client) para vários cenários:
### Executar Exemplos
```bash
# Primeiro terminal — servidor
cargo run --example <nome_servidor> --features dev-certs
# Segundo terminal — cliente
cargo run --example <nome_cliente> --features dev-certs
```
### Lista de Exemplos
| `echo_server` / `echo_client` | Servidor echo básico | 7777/7778 |
| `chat_server` / `chat_client` | Chat em tempo real com salas e nicknames | 7777/7778 |
| `remote_cmd_server` / `remote_cmd_client` | Execução remota de comandos via rede | 8877/8878 |
| `telemetry_server` / `telemetry_client` | Streaming de dados IoT/sensores em tempo real | 9001/9002 |
| `file_transfer_server` / `file_transfer_client` | Upload/download de arquivos encriptados | 9101/9102 |
| `game_sync_server` | Sincronização de estado de jogo (posições, ações) | 9201/9202 |
### Exemplo: Chat
```bash
# Terminal 1
cargo run --example chat_server --features dev-certs
# Terminal 2 (e mais terminais para outros clientes)
cargo run --example chat_client --features dev-certs
```
Comandos do chat:
- `/nick <nome>` — mudar nickname
- `/list` — listar usuários online
- `/quit` — desconectar
### Exemplo: Comandos Remotos
```bash
# Terminal 1
cargo run --example remote_cmd_server --features dev-certs
# Terminal 2
cargo run --example remote_cmd_client --features dev-certs
```
Comandos:
- `CMD:ls -la` — executar comando shell
- `SET:chave=valor` — armazenar key-value
- `PING` — verificar latência
---
## 17. Perguntas Frequentes
### O client precisa do endereço UDP ou TCP?
O **TCP**. O `SecureSocket::connect()` recebe o endereço TCP do servidor. O endereço UDP é trocado automaticamente durante o handshake TLS.
### Quantos clientes o servidor suporta?
Não há limite definido no protocolo. O limite prático depende da sua máquina e aplicação. O `peer_id` é `u16`, então o limite teórico é 65.535 peers por servidor.
### O que acontece se o UDP for bloqueado?
Use o `HybridSocket` (módulo `tcp`) para fallback automático para TCP.
### Como saber se um peer crashou?
O timeout padrão é 10 segundos. Após esse período sem receber dados de um peer, um `SecureEvent::Disconnected` é gerado automaticamente.
### Posso mudar o timeout?
O timeout é configurado no `PeerConfig`. O padrão é `Some(Duration::from_secs(10))`. Para alterar, você precisaria modificar o `PeerConfig` antes de criar o socket (atualmente definido no código-fonte).
### Qual a diferença entre Reliable e ReliableOrdered?
- **Reliable**: garante entrega, mas os pacotes podem chegar em qualquer ordem
- **ReliableOrdered**: garante entrega E ordem, mas um pacote perdido bloqueia os seguintes até ser retransmitido (head-of-line blocking)
### Posso enviar dados antes do evento Connected?
Não. Aguarde o `SecureEvent::Connected` antes de chamar `send()`. O handshake TLS precisa ser completado primeiro.
### Os dados são realmente encriptados?
Sim! Todos os pacotes UDP são encriptados com **ChaCha20-Poly1305** (AEAD). As chaves são trocadas via **TLS 1.3** durante o handshake TCP. Cada pacote inclui um tag de autenticação que previne adulteração.
### Qual o tamanho máximo de um pacote?
O tamanho máximo do payload é definido por `MAX_PACKET_SIZE` no código-fonte. Pacotes maiores são fragmentados automaticamente pelo sistema de canais.
---
<p align="center">
Feito com ⚡ para desenvolvedores que exigem velocidade e segurança
</p>