Cena conhecida: requisições curtas voam como andorinhas, mas quando você inicia um upload grande ou baixa um arquivo pesado via proxy móvel, a conexão cai no meio. Arquivo em 40 por cento, depois o silêncio. Repetir a requisição às vezes ajuda, às vezes não. E o pior: os logs não dizem nada, o servidor parece vivo, mas os dados não chegam. Se você já passou por isso, veio ao lugar certo.

Este artigo não é sobre códigos de resposta nem sobre lógica de tentativas no nível HTTP (há um material separado sobre 429 e backoff exponencial, ao qual vamos nos referir). Aqui vamos analisar o nível de transporte: por que o TCP se rompe, quem exatamente derruba a conexão, como funcionam três timeouts diferentes no caminho do pacote, o que é MTU e fragmentação em redes celulares, e por que a troca de estação base mata sessões longas. E o principal: vamos construir um cliente que sobrevive a tudo isso.

Introdução: o download cai no meio, as requisições curtas passam

Por que esse tema é tão relevante justamente em 2026? Porque proxies móveis se tornaram ferramenta de trabalho para scraping, automação, testes e integração com marketplaces. A rede celular é, por natureza, mais instável que a cabeada. Ela foi projetada para uma pessoa com celular que abre uma página, lê e fecha. Não foi projetada para uma máquina que mantém uma conexão TCP aberta por dez minutos e baixa gigabytes por ela.

Daí o paradoxo destacado no título da seção. Requisições curtas passam porque conseguem terminar antes que qualquer timeout seja atingido ou que ocorra um handover (troca entre estações base). Operações longas duram mais e, portanto, aumentam a chance de encontrar cada um dos problemas: timeout por inatividade, queda na troca de célula, perda de pacotes grandes por MTU incorreto.

O que você vai aprender ao ler até o final:

  • Como descobrir em cinco minutos quem exatamente derrubou a conexão: seu cliente, o proxy, a operadora ou o servidor de destino.
  • Como TCP keepalive é fundamentalmente diferente de HTTP keep-alive e por que você precisa das duas configurações.
  • Como medir os três timeouts no caminho e encontrar o menor, que é o que decide o destino da conexão.
  • Por que em redes celulares a MTU é menor que os padrões 1500 bytes e como é uma falha de PMTUD (sintoma: travamento em respostas grandes).
  • Código pronto de cliente em Python e Node com download por Range, divisão de upload e timeouts adequados.

Vamos falar em linguagem técnica, mas explicar cada termo de forma humana. Vamos nessa.

Fundamentos: como funciona uma conexão via proxy móvel

Antes de analisar as falhas, vamos alinhar nossa visão do cenário. Quando você faz uma requisição via proxy móvel, o pacote percorre uma longa cadeia. Entender essa cadeia é metade do sucesso no diagnóstico.

O caminho do pacote, do cliente ao servidor

Imagine a rota de uma encomenda. Ela passa por etapas e, em cada uma, pode ser atrasada ou extraviada:

  1. Seu cliente — o programa que faz a requisição. Ele tem seus próprios timeouts e configurações de socket.
  2. Servidor de proxy — recebe sua conexão e abre a dele para o destino. Muitas vezes, são duas conexões TCP distintas, unidas.
  3. Modem móvel e interface de rádio — o trecho estreito e instável. Aqui, o pacote viaja pela onda de rádio até a estação base.
  4. Núcleo da rede da operadora — NAT, gateways, sistemas de priorização de tráfego.
  5. Internet pública — canais de backbone até o data center do destino.
  6. Servidor de destino — o ponto final, que também tem seus próprios limites de duração de conexão.

Insight fundamental: a conexão via proxy não é um tubo único, mas pelo menos dois. O cliente mantém uma conexão com o proxy, e o proxy mantém uma conexão com o destino. A queda pode acontecer em qualquer um desses segmentos, e os sintomas serão diferentes.

O que é uma sessão e por que ela é frágil

Uma conexão TCP é um canal virtual. Fisicamente, não existe fio entre você e o servidor: há um acordo entre as duas partes de que elas trocam bytes numerados. Enquanto ambas as partes lembram dos números e do estado, a conexão vive. Quando uma das partes esquece o estado (o NAT reiniciou, o timeout expirou, a célula mudou), a conexão está, na prática, morta, mesmo que a outra parte ainda não saiba disso por um bom tempo.

É exatamente isso que cria as traiçoeiras conexões meio abertas (half-open): um lado acha que o canal está vivo e espera dados, enquanto o outro já esqueceu de tudo. O cliente fica pendurado, nenhum erro chega, o tempo passa. Parece familiar?

Três níveis onde os problemas acontecem

  • Nível de rádio — perda de pacotes, latência, troca de célula. A natureza da rede celular.
  • Nível de rede — timeouts de NAT da operadora, MTU, fragmentação.
  • Nível de aplicação — timeouts do servidor HTTP do proxy e do destino, limites no tamanho do corpo da resposta.

A seguir, vamos passar por cada um e aprender a diferenciá-los.

Mergulho profundo: quem pode derrubar a conexão e como descobrir quem é

Esta é a seção de diagnóstico mais importante. Enquanto você não sabe quem é o culpado, está atirando no escuro. A boa notícia: cada culpado tem uma assinatura própria.

Quatro suspeitos

1. Seu cliente. O culpado mais comum e o mais subestimado. Bibliotecas HTTP têm timeouts padrão que você pode não ter notado. Por exemplo, timeout para o tempo total da requisição, timeout de leitura do socket, timeout de inatividade. Se seu cliente derrubou a conexão sozinho, os logs vão mostrar um erro do tipo read timeout ou socket timeout, com seu código no stack trace.

2. Servidor de proxy. O proxy tem seus próprios limites: tempo máximo de vida da conexão, idle timeout, tamanho máximo da resposta. Quando o proxy derruba a conexão, você geralmente recebe um connection reset súbito ou o fechamento sem resposta no meio da transmissão do corpo. Nesse caso, o ping até o proxy funciona e as requisições curtas também.

3. Operadora de telefonia. O mais invisível. As tabelas NAT das operadoras têm um tempo de vida para cada registro. Se não há tráfego na conexão por um tempo, a operadora remove o registro do NAT e os próximos pacotes simplesmente não têm para onde ir. Sintoma: a conexão trava justamente durante pausas, e não durante transmissão ativa. A operadora também é a culpada na troca de estação base.

4. Servidor de destino. Ele tem suas próprias configurações de keep-alive e limites. Muitos servidores fecham a conexão após N requisições ou após T segundos. Sintoma: o servidor envia o cabeçalho Connection: close ou encerra a conexão de forma correta (FIN), em vez de derrubá-la (RST).

Diagnóstico pelos sintomas: tabela de assinaturas

Vamos analisar os sinais típicos para que você identifique o culpado em minutos.

  • Queda apenas durante pausas; na transmissão ativa, tudo funciona — quase certamente é timeout de NAT da operadora ou idle timeout do proxy. Resolve-se com tráfego de keepalive.
  • Queda sempre em aproximadamente o mesmo volume de dados (por exemplo, em torno de 8 ou 10 megabytes) — limite de tamanho de resposta do proxy ou do servidor. Resolve-se com divisão via Range.
  • Queda sempre em aproximadamente o mesmo tempo (por exemplo, exatamente 60 ou 300 segundos) — limite rígido de duração da conexão. Procure o menor dos timeouts.
  • Travamento justamente em respostas grandes; as pequenas passam — clássica falha de PMTUD e problema de MTU. Há uma seção inteira sobre isso abaixo.
  • Quedas aleatórias sem relação com volume ou tempo, mais frequentes em movimento — troca de estação base, handover, degradação do sinal de rádio.
  • RST imediato ao tentar enviar dados — a conexão já está morta em um dos lados (meio aberta) ou há um reset ativo do proxy.

Ferramentas de diagnóstico inicial

Para distinguir FIN (fechamento educado) de RST (reset abrupto) e entender em qual segmento a conexão cai, use:

  • Logs no nível de socket — registre o horário exato da queda, a quantidade de bytes transferidos e o tipo de exceção.
  • Análise de tráfego — uma ferramenta de captura de pacotes mostrará quem enviou RST ou FIN. Se o RST vem do endereço do proxy, a culpa é do proxy. Se a conexão simplesmente fica muda, sem pacotes, a culpa é de um nó intermediário (a operadora).
  • Medições de controle — repita a mesma operação usando uma conexão cabeada direta. Se pela cabo tudo fica estável e pelo proxy móvel cai, o problema está no segmento móvel.

Observação do autor: em 70% dos casos que analisamos, o culpado era o timeout de NAT da operadora ou o idle timeout padrão, e não o proxy ou o servidor. As pessoas culpam o proxy, mas a solução está em algumas linhas de configuração do socket.

Keep-alive e idle timeout: três timeouts no caminho, o menor vence

Este é o princípio fundamental que vale a pena gravar na memória: no caminho do pacote existem vários timeouts de inatividade independentes, e o destino da conexão é decidido pelo menor deles. É como uma corrente: ela rompe no elo mais fraco.

Onde moram os timeouts

  1. Idle timeout do seu cliente. Quanto tempo seu programa está disposto a esperar por dados sem receber nada. Por padrão, em diferentes bibliotecas, varia de 30 segundos a infinito.
  2. Idle timeout do proxy. Quanto tempo o proxy mantém uma conexão ociosa aberta. Valores típicos: de 60 a 300 segundos.
  3. Timeout de NAT da operadora. Quanto tempo o núcleo da rede mantém o registro de tradução de endereços sem tráfego. Para TCP, normalmente é de 300 a 600 segundos, mas para UDP e em horários de pico pode ser de 30 a 60 segundos.
  4. Keep-alive timeout do servidor de destino. Quanto tempo o servidor mantém a conexão entre requisições. Geralmente de 5 a 75 segundos.

Imagine que o cliente está disposto a esperar 120 segundos, o proxy derruba aos 90, e a operadora limpa o NAT aos 60. Quem vence? A operadora. A conexão morre aos 60 segundos de inatividade, e nem o cliente nem o proxy ficam sabendo imediatamente.

Como medir o menor timeout

A metodologia é simples e confiável. Estabelecemos a conexão, fazemos uma requisição, depois ficamos em silêncio e esperamos, cronometrando o tempo até a queda. Repetimos algumas vezes para eliminar o acaso.

  1. Abra uma conexão via proxy para um servidor de teste que suporte keep-alive.
  2. Faça uma requisição curta e receba a resposta.
  3. Não feche a conexão. Inicie o cronômetro.
  4. Periodicamente (a cada segundo), verifique se a conexão está viva, tentando ler do socket em modo não bloqueante.
  5. Registre o momento em que chega um RST, um FIN ou o socket fica ilegível.

Faça a medição três vezes. Se a queda acontece consistentemente em torno de 60 segundos, esse é o seu teto de inatividade. Isso significa que o tráfego de keepalive precisa ser enviado com mais frequência do que uma vez a cada 60 segundos, com boa margem — por exemplo, a cada 20-25 segundos.

Estratégia para vencer o idle timeout

Já que o menor timeout decide tudo, nossa tarefa é não deixar a conexão ociosa além desse limite. Duas abordagens:

  • Preencher a conexão com tráfego útil — durante a transmissão ativa de dados, os idle timeouts não são acionados, porque não há inatividade. Por isso, um download contínuo raramente sofre com idle timeout; ele sofre, sim, com limites de tamanho e de duração.
  • Enviar sondas de keepalive nas pausas — quando não há dados úteis (por exemplo, enquanto o servidor gera um relatório), é preciso manter a conexão com tráfego artificial. É aqui que entram os dois mecanismos de keep-alive, que vamos detalhar separadamente.

TCP keepalive versus HTTP keep-alive: mecanismos diferentes, você precisa dos dois

Uma confusão enorme na indústria nasce de nomes parecidos. TCP keepalive e HTTP keep-alive são coisas completamente diferentes, que atuam em níveis distintos. E para um cliente móvel resiliente, você precisa dos dois.

HTTP keep-alive: reutilização da conexão

HTTP keep-alive (também chamado de conexão persistente) serve para não abrir uma nova conexão TCP a cada requisição. Em vez disso, uma única conexão atende várias requisições em sequência. Isso é nível de aplicação.

Por que isso é importante para redes móveis? Estabelecer uma nova conexão TCP via rede celular é caro. O three-way handshake, mais o handshake TLS se houver criptografia, pode levar centenas de milissegundos em um canal de rádio com alta latência. Ao reutilizar a conexão, você economiza esse tempo a cada requisição seguinte.

Mas! O HTTP keep-alive não ajuda em nada contra o timeout de NAT da operadora durante as pausas. Ele apenas permite manter a conexão aberta para a próxima requisição, mas, por si só, não gera tráfego nos intervalos.

TCP keepalive: o pulso no nível de transporte

TCP keepalive é um mecanismo do próprio protocolo TCP. O sistema operacional envia periodicamente um pacote de serviço vazio (sonda keepalive) para verificar se o outro lado está vivo e, de quebra, atualizar os registros nas tabelas NAT intermediárias. Isso é nível de kernel do SO.

É o TCP keepalive que é sua principal arma contra os timeouts de NAT da operadora e os idle timeouts de nós intermediários. Cada sonda é tráfego que zera o contador de inatividade em todo o caminho.

O TCP keepalive tem três parâmetros-chave:

  • keepalive idle (ou keepalive time) — depois de quantos segundos de inatividade começar a enviar sondas. O padrão na maioria dos SOs é 7200 segundos, ou seja, duas horas. Uma catástrofe para redes móveis.
  • keepalive interval — o intervalo entre as sondas, se não houver resposta.
  • keepalive count (probes) — quantas sondas sem resposta em sequência são consideradas sinal de conexão morta.

Valores recomendados para redes móveis

As duas horas padrão não servem de forma alguma. A operadora vai limpar o NAT muito antes da primeira sonda. Estes são os valores que funcionam, validados na prática:

  • keepalive idle: 15-25 segundos. Começamos a enviar sondas após uma pausa curta, para garantir que vamos nos adiantar até ao timeout de NAT mais agressivo.
  • keepalive interval: 10-15 segundos. Se a sonda não chegou, repetimos em um intervalo curto.
  • keepalive count: 3-4. Depois de três ou quatro sondas sem resposta, consideramos a conexão morta e a restabelecemos, em vez de ficarmos pendurados para sempre.

Essa combinação traz um benefício duplo: a conexão não é derrubada pela operadora nas pausas e, se mesmo assim morrer (por exemplo, por causa de um handover), o cliente fica sabendo em 45-70 segundos, e não depois de horas. Detectar rapidamente uma conexão morta é metade da resiliência.

Por que você precisa das duas configurações

Uma analogia. HTTP keep-alive é como deixar uma sala de reunião reservada o dia inteiro, para não precisar reservar de novo toda vez. Já o TCP keepalive é entrar na sala periodicamente, para o pessoal da limpeza não achar que ela está vazia e trancar a porta. Você reserva, mas não entra — eles trancam. Você entra, mas reserva tudo de novo a cada vez — perde tempo. Precisa dos dois.

MTU e fragmentação: por que os pacotes são menores em redes celulares

Agora vamos à causa mais subestimada de travamentos. Se respostas pequenas passam e as grandes travam completamente, com 90% de probabilidade o problema é MTU e PMTUD quebrado.

O que é MTU em palavras simples

MTU (Maximum Transmission Unit) é o tamanho máximo de um pacote que pode ser enviado à rede sem fragmentação. No Ethernet clássico, são 1500 bytes. Pense nisso como a largura de uma porta: móveis mais largos que a porta precisam ser desmontados para passar.

O problema é que, em redes celulares, a MTU efetiva costuma ser inferior a 1500. O motivo é a encapsulação. O tráfego móvel é envolvido em camadas adicionais de protocolo dentro da rede da operadora. Cada camada adiciona seus próprios bytes de cabeçalho, sobrando menos espaço para os dados úteis. A MTU real de trabalho em redes celulares frequentemente fica na faixa de 1400-1480 bytes, às vezes até menos.

O que é PMTUD e por que ele quebra

PMTUD (Path MTU Discovery) é o mecanismo de descoberta automática do tamanho máximo de pacote em todo o caminho. Funciona assim: o cliente envia um pacote grande com o flag Don't Fragment (não fragmentar). Se no caminho houver um nó com MTU menor, esse nó descarta o pacote e envia de volta uma mensagem ICMP especial do tipo fragmentation needed, informando o tamanho permitido. O cliente recebe a dica e reduz o tamanho dos pacotes.

É um esquema bonito. Mas ele depende de uma condição frágil: as mensagens ICMP precisam voltar até o cliente. Na prática, muitas redes, firewalls e configurações de segurança bloqueiam ICMP por completo. E é aí que acontece a catástrofe chamada PMTUD black hole (buraco negro).

Como é uma falha de PMTUD: anatomia do travamento

O cenário é clássico e bem característico:

  1. O cliente estabelece a conexão. O handshake acontece com pacotes pequenos — tudo certo.
  2. O cliente envia uma requisição curta — o pacote pequeno passa, a resposta chega. Respostas pequenas funcionam.
  3. O servidor começa a enviar uma resposta grande com pacotes de tamanho cheio, de 1500 bytes, com o flag Don't Fragment.
  4. Em algum ponto do caminho, um nó com MTU 1400 descarta esses pacotes porque eles são maiores e não podem ser fragmentados.
  5. O nó envia de volta o ICMP fragmentation needed, mas esse ICMP é bloqueado pelo firewall e não chega.
  6. O servidor não recebe a dica, continua enviando os mesmos pacotes grandes, que são descartados de novo. Um loop infinito.
  7. Resultado: pacotes pequenos (cabeçalhos, ACKs) passam, mas os dados da resposta não. A conexão trava completamente no meio de uma resposta grande.

É por isso que requisições curtas passam e respostas grandes travam. Não é misticismo, é o buraco negro de PMTUD. E essa é, provavelmente, a fonte mais comum de cabelos brancos entre engenheiros que trabalham com tráfego móvel.

Como tratar o problema de MTU

Há vários níveis de solução, do nível de aplicação ao de rede:

  • MSS clamping. O método mais confiável no nível de rede. MSS (Maximum Segment Size) é o tamanho máximo do segmento TCP que as partes negociam logo no início, durante o handshake. Se você limitar explicitamente o MSS para que o pacote final caiba na MTU real (por exemplo, MSS 1360-1400), o servidor vai enviar pacotes do tamanho certo desde o início, e nenhum ICMP será necessário. Isso resolve o buraco negro na raiz.
  • Redução da MTU da interface. Se você gerencia o modem ou a máquina por onde o tráfego passa, pode definir a MTU da interface para 1400 ou menos. Assim, todos os pacotes de saída ficam automaticamente dentro do tamanho seguro.
  • Permitir a passagem de ICMP. Se você tem controle sobre os firewalls no caminho, libere mensagens ICMP do tipo fragmentation needed. Assim, o PMTUD padrão funciona como planejado.
  • Nível de aplicação. Se você baixa um arquivo grande, divida-o em partes usando requisições Range. Cada parte é uma transmissão curta e isolada, com menos chance de esbarrar em problemas de fluxos grandes. Vamos falar disso em detalhe na seção prática.

Insight: mesmo que você não gerencie a rede, quase sempre consegue influenciar o MSS pelas configurações da conexão ou pelos parâmetros do serviço de proxy. Um bom provedor de proxy móvel já configura o MSS clamping correto no lado dele, poupando você de buracos negros. Esse é um dos critérios de qualidade do serviço.

Troca de estação base e transição entre redes: por que o TCP não sobrevive a isso

Agora, a incompatibilidade mais fundamental. A rede celular foi criada para a mobilidade, mas o TCP não. E isso é um conflito no nível da arquitetura.

Por que o TCP é amarrado ao endereço

Uma conexão TCP é definida de forma única por uma quádrupla: endereço de origem, porta de origem, endereço de destino, porta de destino. É como o endereço postal da conexão. Se qualquer um desses elementos mudar, já é outra conexão, e a antiga se torna inválida.

E o que acontece em uma rede móvel? Em alguns cenários de troca de estação base ou transição entre tecnologias (por exemplo, entre gerações diferentes de rede ou entre redes), o endereço IP externo do nó móvel pode mudar. É aí que o TCP se mostra impotente: ele não sabe continuar uma conexão com um novo endereço. A conexão antiga simplesmente morre. Todos os dados que estavam em trânsito são perdidos.

Handover: nem sempre fatal, mas sempre arriscado

Para ser justo, as redes modernas tentam tornar o handover transparente: manter o mesmo IP durante a troca de célula. Muitas vezes isso funciona e você nem percebe. Mas, às vezes, acontece troca de IP, uma interrupção curta no rádio por um ou dois segundos, ou um pico de perda de pacotes. Para uma requisição curta, isso é imperceptível. Para uma sessão de dez minutos, é uma loteria em que você joga toda vez.

Sintomas de queda durante o handover

  • As quedas são aleatórias, sem relação com volume de dados ou tempo.
  • A frequência das quedas aumenta se o dispositivo está fisicamente em movimento (o que é típico de proxies móveis com SIMs reais).
  • Depois da queda, uma nova conexão é estabelecida normalmente — a rede está viva; apenas a conexão antiga morreu.

O que fazer: aceitar e construir resiliência

Não dá para vencer a troca de IP no nível do TCP. Mas dá para construir um cliente para o qual a queda de conexão é uma situação normal, não uma emergência. A filosofia é simples: a conexão via rede móvel é efêmera por definição, e o cliente precisa saber restabelecê-la sem atrito e continuar o trabalho de onde parou.

Estas são as técnicas que vamos implementar no código:

  • Idempotência das operações. Projete as requisições para que possam ser repetidas com segurança. Baixar via Range é idempotente: repetir a requisição do mesmo intervalo de bytes dá o mesmo resultado.
  • Retomar, não recomeçar. Em uma queda, não reinicie o arquivo do zero; continue do último byte recebido. Isso economiza tráfego e tempo.
  • Detecção rápida de conexão morta. Com TCP keepalives agressivos, como falamos, você descobre uma conexão morta em segundos, não em minutos.
  • Transações curtas. Quanto mais curta a transmissão individual, menor a chance de um handover pegá-la exatamente no meio. Dividir um upload grande em partes é uma consequência direta desse princípio.

Na prática com Python: cliente resiliente com retomada e timeouts

Chega de teoria, vamos construir. Começando com Python. Vamos montar um cliente que: configura TCP keepalive, define timeouts razoáveis, baixa arquivos em partes via Range e consegue retomar após uma queda.

Passo 1: configurando TCP keepalive no socket

As bibliotecas HTTP padrão não configuram keepalive agressivo por padrão. É preciso chegar ao socket. No ecossistema do requests, isso é feito por meio de um adaptador de transporte próprio, que define as opções do socket: liga o keepalive, define idle de 20 segundos, interval de 10 segundos e count 3. Em termos de descrição, a lógica é: registramos um adaptador que, ao criar a conexão, ajusta os parâmetros no nível baixo.

A parte essencial da configuração, em pseudocódigo: ativar a opção SO_KEEPALIVE, depois definir TCP_KEEPIDLE como 20, TCP_KEEPINTVL como 10 e TCP_KEEPCNT como 3. Os nomes das opções variam um pouco entre sistemas operacionais, então, em produção, elas são escolhidas com uma verificação de plataforma.

Passo 2: timeouts razoáveis

Regra fundamental: sempre defina timeouts explicitamente e separe o timeout de conexão do timeout de leitura. O padrão sem timeout é uma armadilha em que o cliente fica pendurado para sempre em uma conexão meio aberta.

  • Connect timeout: 10 segundos. Estabelecer uma conexão via rede móvel é mais lento, mas 10 segundos dão uma margem confortável.
  • Read timeout: 30 segundos. Esse é o timeout de inatividade entre blocos de dados, não da transmissão inteira. Se nenhum byte chegar em 30 segundos, consideramos a conexão problemática.
  • Orçamento total da operação deve ser controlado separadamente, na lógica de retomada, e não com um timeout gigante para a requisição inteira.

Passo 3: download via Range com retomada

A ideia do algoritmo. Abrimos o arquivo de destino para escrita. Descobrimos o tamanho já baixado (se o arquivo existir parcialmente). Solicitamos o intervalo restante via cabeçalho Range: bytes, da posição atual até o fim. Escrevemos o fluxo no arquivo conforme os dados chegam. Se houver uma queda (exceção de leitura, conexão rompida), não entramos em pânico: olhamos novamente quantos bytes já estão no disco e repetimos a requisição a partir da nova posição inicial. Seguimos assim até o arquivo ser recebido por completo.

  1. Descobrir o tamanho total do arquivo com uma requisição de cabeçalhos (HEAD ou GET com Range: bytes=0-0, para ler o Content-Range).
  2. Verificar o tamanho local da parte já baixada.
  3. Se o tamanho local for igual ao total, o arquivo está pronto; saímos.
  4. Caso contrário, montar uma requisição com Range começando do tamanho local.
  5. Ler a resposta em blocos de 64 a 256 kilobytes, acrescentando ao arquivo.
  6. Ao concluir com sucesso, verificar a integridade (tamanho e, se possível, soma de verificação).
  7. Em caso de queda, incrementar o contador de tentativas, aplicar uma pausa curta e voltar ao passo 2.
  8. Limitar o número máximo de tentativas no nível de transporte (por exemplo, 5 a 8), para não ficar em loop infinito diante de um problema sistêmico.

Um detalhe importante: certifique-se de que o servidor suporta Range. O sinal é o cabeçalho Accept-Ranges: bytes na resposta e o código 206 Partial Content em uma requisição Range. Se o servidor responde com 200 e ignora o Range, a retomada não é possível e será preciso baixar tudo de novo — nesse caso, keepalive e MSS correto são ainda mais importantes.

Passo 4: dividindo uploads grandes

Quando você não está baixando, mas enviando um volume grande (por exemplo, enviando dados ou recebendo um relatório grande), aplique o mesmo princípio de divisão. Divida a tarefa em páginas ou chunks de tamanho fixo. Cada chunk é uma transação curta e isolada, com tratamento de erros próprio. Mantenha um log de progresso: quais chunks já foram confirmados. Em caso de queda, repita apenas os não confirmados. Isso transforma uma operação frágil de dez minutos em uma série de operações curtas e resilientes.

Sobre estratégias de repetição por códigos de resposta do servidor — não vamos tratá-las aqui, porque esse é o tema de um material separado sobre 429 e backoff exponencial, que vale a pena ler depois deste artigo. Nosso foco é o transporte: queda, timeout, tamanho.

Na prática com Node.js: agente HTTP resiliente e streaming

Agora, o mesmo conjunto de princípios no ecossistema Node.js. Aqui, o papel central é do objeto de agente, que gerencia o pool de conexões.

Passo 1: configurando o agente com keep-alive

No Node, cria-se um agente HTTP ou HTTPS com keepAlive ativado. O parâmetro keepAlive true faz o agente reutilizar as conexões (isso é o nível HTTP). Além disso, define-se keepAliveMsecs — o intervalo com que as sondas TCP keepalive são enviadas no nível do socket. Para redes móveis, configure keepAliveMsecs na faixa de 15000 a 20000 milissegundos, para se adiantar ao timeout de NAT da operadora. Também limite maxSockets e maxFreeSockets para não criar conexões desnecessárias.

Passo 2: timeouts em diferentes níveis

No Node, os timeouts são definidos em vários lugares, e é importante não esquecer nenhum:

  • Timeout de conexão — por meio de uma opção na requisição ou de um handler para o evento de conexão do socket.
  • Timeout de inatividade do socket — um método que define o timeout do socket. Quando ele dispara, é preciso destruir o socket explicitamente e tratar isso como uma queda. O Node não fecha o socket automaticamente no timeout; ele apenas emite o evento — isso é algo de que muitos esquecem, e a conexão continua pendurada.
  • Tratamento dos eventos error e close na requisição e no socket — cada um deve levar a uma lógica controlada de nova tentativa.

Os valores recomendados são análogos aos do Python: connect em torno de 10 segundos, idle do socket em torno de 30 segundos, sondas keepalive a cada 15-20 segundos.

Passo 3: streaming de download com retomada

No Node, é natural trabalhar com streams. A lógica de retomada é a mesma do Python: verificamos o tamanho do arquivo local, abrimos um stream de escrita no modo de adição, montamos uma requisição com o cabeçalho Range a partir do tamanho atual, e registramos handlers para os eventos data, end e error. No evento data, escrevemos o chunk no arquivo. No evento end, verificamos se o arquivo foi totalmente recebido. No evento error ou em um close prematuro, quando menos bytes do que o esperado foram recebidos, iniciamos uma nova tentativa a partir da nova posição.

O ponto-chave da resiliência no Node é o tratamento correto do encerramento prematuro do stream. O evento end pode ocorrer mesmo que nem tudo tenha sido recebido, se a conexão cair. Por isso, sempre compare o volume efetivamente recebido com o esperado nos cabeçalhos Content-Length ou Content-Range. Não confie apenas no disparo do end.

Passo 4: envolvendo as tentativas no nível de transporte

Envolva toda a operação de download em um loop com número limitado de tentativas. Entre as tentativas, uma pausa curta (para quedas de transporte, 1 a 3 segundos são suficientes, porque a causa não é sobrecarga do servidor, mas um evento de rede). Conte as tentativas. Ao esgotar o limite, propague o erro para cima com informações de diagnóstico: quantos bytes foram recebidos, qual foi o tipo de erro e quantas tentativas foram feitas. Esse diagnóstico é inestimável na análise de incidentes.

Erros típicos: o que não fazer

Vamos analisar os antipadrões que encontramos com frequência em código alheio. Evite-os e metade dos problemas desaparece.

Erro 1: não definir timeouts explícitos

O mais comum e o mais doloroso. Um cliente sem timeout em uma conexão meio aberta fica pendurado para sempre. A thread fica bloqueada, o recurso não é liberado, e você acha que a operação ainda está em andamento. Sempre defina timeouts explicitamente. A ausência de timeout não é paciência infinita, é uma bomba escondida.

Erro 2: contar com o TCP keepalive padrão

As duas horas padrão tornam o TCP keepalive inútil para redes móveis. Muitos ativam o SO_KEEPALIVE e ficam tranquilos, sem desconfiar que a primeira sonda só sairá depois de 7200 segundos, quando a operadora já limpou tudo há muito tempo. Configure idle, interval e count explicitamente.

Erro 3: baixar o arquivo inteiro de novo a cada queda

Uma queda aos 95 por cento e reiniciar tudo do zero não é só tempo perdido, é também um consumo extra de tráfego móvel, que normalmente é tarifado no proxy. A retomada via Range é obrigatória para qualquer download grande.

Erro 4: ignorar MTU e MSS

As pessoas passam meses brigando com travamentos em respostas grandes, trocando timeouts e proxies, quando a causa é o buraco negro de PMTUD. Se respostas grandes travam e as pequenas passam, verifique a MTU primeiro e configure o MSS clamping. Isso vai poupar semanas da sua vida.

Erro 5: confundir quedas de transporte com respostas do servidor

Uma queda de transporte (RST, timeout de leitura, socket morto) e uma resposta do servidor com código de erro são situações diferentes, com estratégias de reação diferentes. Para quedas de transporte, são adequadas novas tentativas rápidas com pausa curta e retomada. Para respostas do servidor com códigos como 429, é preciso backoff exponencial — e isso é tema de outro artigo. Não misture essas duas camadas em um único handler.

Erro 6: tentativas agressivas demais

Um loop infinito de tentativas sem limite, diante de um problema sistêmico (por exemplo, proxy totalmente indisponível), vira uma carga parasitária. Sempre estabeleça um teto para o número de tentativas e encerre a operação de forma consciente, com diagnóstico.

Erro 7: não verificar a integridade do resultado

O fato de o download ter terminado não é igual ao fato de os dados estarem corretos. Uma queda pode deixar um arquivo truncado que, por todos os sinais formais, parece completo. Sempre confira o tamanho e, para dados importantes, a soma de verificação.

Erro 8: manter uma conexão por tempo demais

Quanto mais tempo uma conexão via rede móvel fica viva, maior a probabilidade acumulada de encontrar um handover, uma troca de IP ou um timeout de NAT. Restabelecer a conexão periodicamente não é fraqueza, é higiene inteligente. Não tenha medo de recriar conexões.

Ferramentas e recursos para diagnóstico e construção de resiliência

A ferramenta certa economiza horas. Este é o arsenal que vale a pena manter à mão.

Diagnóstico de rede e pacotes

  • Captura e análise de tráfego. Uma ferramenta de captura de pacotes é o seu microscópio. Ela mostra quem enviou o RST, se o ICMP fragmentation needed chegou, qual o tamanho real dos pacotes e onde o fluxo é interrompido. Sem ela, o diagnóstico de MTU e a identificação do culpado da queda viram adivinhação.
  • Utilitários de verificação de caminho. Ferramentas de traceroute e verificação de MTU ajudam a entender onde o tamanho do pacote cai no caminho. Há modos que procuram diretamente o maior tamanho de pacote que passa — exatamente o que você precisa para configurar o MSS.
  • Servidores eco de teste. Um servidor simples que sabe manter keep-alive e entregar dados de um tamanho definido é indispensável para medir idle timeouts e reproduzir problemas com respostas grandes em condições controladas.

Bibliotecas e abordagens para o cliente

  • Clientes HTTP com configuração flexível de sockets. Escolha bibliotecas que dão acesso aos parâmetros da conexão e permitem definir timeouts e keepalive no nível baixo.
  • Mecanismos de streaming. O processamento em fluxo do corpo da resposta é obrigatório para downloads grandes — você não pode manter a resposta inteira na memória.
  • Registro de progresso. Um armazenamento de estado simples (quais chunks foram recebidos, quantos bytes há no disco) transforma a retomada em uma tarefa trivial.

Qualidade da infraestrutura de proxy

Vale reforçar: grande parte dos problemas de transporte é resolvida no lado do provedor de proxy. Um MSS clamping bem configurado, idle timeouts adequados, manutenção estável do IP durante handovers e um trabalho transparente com keep-alive são sinais de um serviço maduro. Serviços como o MobileProxy.space projetam a infraestrutura levando em conta essas nuances de transporte, o que tira parte da dor de cabeça do cliente. Mas, mesmo com um proxy ideal, o cliente precisa ser resiliente — porque o canal de rádio é imprevisível por natureza.

Casos e resultados: como isso funciona na prática

Vamos analisar alguns casos generalizados que refletem situações típicas e suas soluções. Os números são médios, mas refletem ordens de grandeza reais.

Caso 1: o upload do catálogo travava no meio

Situação. Uma equipe enviava um grande catálogo de produtos via proxy móvel em uma única requisição. Resposta de cerca de 15 megabytes. Travava consistentemente na faixa de 6 a 8 megabytes, sem erro, apenas silêncio, até que o timeout geral disparasse depois de alguns minutos.

Diagnóstico. As requisições pequenas passavam perfeitamente. A captura de tráfego mostrou que os pacotes grandes saíam com o flag Don't Fragment, e o ICMP fragmentation needed não voltava. Clássico buraco negro de PMTUD.

Solução. Configuramos MSS clamping para um valor que garantisse o pacote dentro da MTU real da rede móvel e dividimos o upload em requisições paginadas de 2 megabytes.

Resultado. Os travamentos desapareceram por completo. O tempo de upload ficou previsível e, em quedas raras, apenas uma página era repetida, não o catálogo inteiro. A taxa de uploads bem-sucedidos saltou de cerca de 40% para praticamente 100%.

Caso 2: a conexão morria durante pausas de espera

Situação. O cliente enviava uma requisição para gerar um relatório pesado; o servidor levava de 90 a 120 segundos para processar e depois devolveria o resultado. Mas, quando o relatório ficava pronto, a conexão já estava morta.

Diagnóstico. A medição do idle timeout mostrou uma queda consistente em cerca de 60 segundos de inatividade. O culpado era o timeout de NAT da operadora: durante a espera, não havia tráfego nenhum.

Solução. Ativamos o TCP keepalive com idle de 20 segundos e interval de 10. Agora, durante a espera, a conexão era renovada por sondas de serviço a cada 20 segundos.

Resultado. A conexão passou a sobreviver até o relatório ficar pronto. As quedas nas pausas cessaram. Um bônus extra: o cliente passou a descobrir conexões realmente mortas em 45 a 60 segundos, em vez de ficar pendurado por minutos.

Caso 3: quedas aleatórias durante scraping ativo

Situação. Sessões de scraping de longa duração caíam de forma caótica, sem relação com volume ou tempo. Especialmente frequentes em determinados horários.

Diagnóstico. Os sinais apontavam para troca de IP durante o handover. Depois da queda, uma nova conexão subia instantaneamente — a rede estava viva.

Solução. Reformulamos o cliente com a filosofia de conexões efêmeras: transações curtas e idempotentes, registro de progresso, restabelecimento rápido da conexão em caso de queda, repetições limitadas com pausa curta.

Resultado. As quedas não desapareceram fisicamente (não dá para vencer a troca de IP), mas deixaram de ser um problema. Cada queda custava a repetição de uma transação curta — frações de segundo. A confiabilidade geral do processo cresceu dramaticamente, e os engenheiros pararam de virar noites olhando logs.

Conclusão geral dos casos

Note o padrão: em todos os casos, a solução não estava em trocar de proxy, mas em entender o nível de transporte e configurar corretamente o cliente. O diagnóstico pelos sintomas apontou o culpado específico, e o tratamento foi cirúrgico e rápido.

FAQ: perguntas frequentes sobre quedas de conexão em redes móveis

Por que, via proxy móvel, requisições curtas funcionam e as longas caem?

Porque operações longas duram mais e acabam encontrando cada um dos problemas de transporte: idle timeout nas pausas, limite de tamanho da resposta, limite de duração da conexão, handover com troca de IP e o buraco negro de PMTUD em pacotes grandes. As requisições curtas terminam antes que qualquer um deles aconteça. A solução é configurar keepalive, MSS e implementar a retomada via Range.

Como saber exatamente quem derruba a conexão — proxy, operadora ou servidor?

Veja a assinatura. Quedas nas pausas — timeout de NAT da operadora ou idle do proxy. Queda em volume fixo — limite de tamanho do proxy ou do servidor. Queda em tempo fixo — limite de duração. Travamento em respostas grandes — MTU e PMTUD. Quedas aleatórias em movimento — handover. Para uma resposta precisa, use a captura de tráfego: ela mostra de qual endereço veio o RST e se o ICMP chegou.

Qual é a diferença entre TCP keepalive e HTTP keep-alive?

O HTTP keep-alive atua no nível de aplicação e permite reutilizar uma mesma conexão para várias requisições, economizando no estabelecimento. O TCP keepalive atua no nível do kernel do SO e envia sondas de serviço periodicamente, mantendo a conexão viva nas pausas e renovando o NAT. O primeiro economiza tempo em novas requisições; o segundo evita a queda por inatividade. Você precisa dos dois.

Quais valores de TCP keepalive definir para redes móveis?

Ponto de partida: idle de 15 a 25 segundos, interval de 10 a 15 segundos, count de 3 a 4. Essa combinação se adianta aos timeouts de NAT agressivos das operadoras e, ao mesmo tempo, garante a detecção rápida de conexões mortas. Ajuste os valores exatos medindo seu próprio idle timeout na operadora e no proxy específicos.

O que é o buraco negro de PMTUD e como reconhecê-lo?

É a situação em que um nó no caminho descarta pacotes grandes demais, mas o aviso ICMP sobre a necessidade de reduzir o tamanho é bloqueado e não chega ao remetente. No fim, os pacotes grandes são perdidos indefinidamente, e os pequenos passam. Reconhece-se pelo sintoma: o handshake e as respostas pequenas funcionam, mas as respostas grandes travam completamente. Trata-se com MSS clamping ou redução da MTU.

É possível manter uma conexão TCP durante a troca de estação base?

Se a rede mantém o mesmo IP externo no handover, sim, a conexão sobrevive à troca, talvez com um pequeno atraso. Se o IP muda, não — a conexão TCP antiga está irreversivelmente morta, porque o TCP é rigidamente ligado ao par de endereços e portas. A estratégia correta não é tentar preservar a conexão a qualquer custo, mas construir um cliente que restabelece a conexão sem atrito e continua de onde parou.

Como retomar corretamente um arquivo após uma queda?

Verifique se o servidor suporta Range (cabeçalho Accept-Ranges: bytes e código 206 em uma requisição Range). Então, na queda, descubra o tamanho da parte já recebida e solicite o restante pelo cabeçalho Range a partir desse byte, acrescentando ao mesmo arquivo. Repita até receber tudo, limitando o número de tentativas. No final, confira o tamanho final com o esperado.

Quais timeouts definir no cliente HTTP para proxy móvel?

Separe o timeout de estabelecimento da conexão (cerca de 10 segundos) do timeout de inatividade de leitura (cerca de 30 segundos, como uma pausa entre blocos de dados, e não a transmissão inteira). Controle o orçamento total da operação na lógica de retomada, e não com um único timeout gigante. Nunca deixe os timeouts ilimitados.

Preciso mudar algo se as estratégias de repetição por códigos de resposta já estão configuradas?

Sim. As repetições por códigos de resposta (por exemplo, tratar 429 com backoff exponencial) são o nível de aplicação, um tema à parte. As quedas de transporte — RST, timeouts de leitura, sockets mortos — exigem uma lógica própria: repetições rápidas com pausa curta, retomada, keepalive e MSS correto. Essas duas camadas não se substituem; elas devem coexistir no cliente.

A escolha do provedor de proxy afeta a resiliência de transporte?

Muito. Um provedor maduro configura MSS clamping, idle timeouts adequados, tenta manter o IP durante handovers e trabalha corretamente com keep-alive. Isso elimina parte dos problemas antes mesmo do seu código. Mas, mesmo com um proxy ideal, continua sendo necessário construir um cliente resiliente, porque o canal de rádio é imprevisível por natureza.

Conclusão: a conexão é efêmera, mas os dados precisam chegar

Cobrimos o caminho do sintoma ao cliente resiliente. Vamos registrar o essencial, para que este artigo vire o seu favorito.

Primeiro. A queda de uma conexão longa via proxy móvel não é misticismo, e sim consequência de mecanismos bem concretos: idle timeouts em três níveis, limites de tamanho e tempo, problemas de MTU e handover. Cada um tem sua assinatura, e o diagnóstico pelos sintomas quase sempre aponta o culpado.

Segundo. O menor timeout no caminho decide o destino da conexão. Meça-o e configure o TCP keepalive de forma mais agressiva que esse limite — idle de 15 a 25 segundos para redes móveis. Não esqueça que TCP keepalive e HTTP keep-alive são mecanismos diferentes e você precisa dos dois.

Terceiro. Se respostas grandes travam e as pequenas passam, quase certamente é o buraco negro de PMTUD. Trata-se com MSS clamping e MTU correta. Não perca semanas mexendo em timeouts; verifique o tamanho do pacote primeiro.

Quarto. A troca de IP no handover não pode ser vencida, mas pode deixar de ser assustadora. Construa o cliente em torno da efemeridade da conexão: transações curtas e idempotentes, retomada via Range, registro de progresso, restabelecimento rápido, repetições limitadas e verificação de integridade obrigatória.

Seus próximos passos são simples. Meça o idle timeout no seu proxy e na sua operadora. Ative e configure o TCP keepalive. Teste o comportamento em respostas grandes e, se necessário, ajuste o MSS. Implemente a retomada via Range. E, claro, estude o material complementar sobre estratégias de repetição no nível dos códigos de resposta — 429 e backoff exponencial — para cobrir também a camada de aplicação, e não só o transporte.

A rede móvel é imprevisível por natureza. Mas um cliente construído com respeito a essa natureza transforma a imprevisibilidade de uma fonte de plantões noturnos em um ruído de fundo rotineiro. A conexão é efêmera — e tudo bem. O importante é que os dados cheguem mesmo assim. Agora você sabe como fazer isso.