É verdade que com todos os avanços nos serviços de streamming que ocorreram nos últimos anos, os torrents têm ficado um pouco para segundo plano. Apesar disso, o protocolo bittorrent continua sendo uma boa alternativa para a disponibilização de arquivos para download na internet, e um caso de estudo interessante para quem tem curiosidade em entender um pouco mais de sistemas distribuídos.
Nesse post, vamos estudar o funcionamento do protocolo Bittorrent e os diversos componentes que compõe o sistema Bittorrent. Mas antes de iniciarmos nosso estudo, é importante lembrar que a palavra Bittorrent pode se referir a 3 coisas diferentes:
1) a um protocolo da camada de aplicação para download de arquivos;
2) a um software proprietário que utiliza esse protocolo; e
3) à empresa que desenvolve esse software.
É importante destacar que embora o software Bittorrent tenha sido o primeiro a utilizar esse protocolo, atualmente existem diversos outros softwares que o utilizam, como o Transmission, o μTorrent e o BitComet. Apesar disso, usuários desses vários softwares podem se comunicar entre si, através do protocolo comum BitTorrent. Daqui em diante, vamos chamar o conjunto de aplicações que fazem uso do protocolo BitTorrent de aplicações bittorrent.


Modelo peer-to-peer

As aplicações que utilizam o protocolo BitTorrent formam um sistema distribuído que segue o modelo peer-to-peer, ou par a par, muitas vezes abreviado para P2P. Diferente do que ocorre em uma arquitetura cliente-servidor, onde os papéis de cada “lado” são bem definidos, com o servidor oferecendo um serviço e o cliente consumindo o mesmo, em uma arquitetura par-a-par, essa distinção fica um tanto borrada, porque cada par do sistema se comporta ora como “servidor” (provendo recursos), ora como “cliente” (consumindo recursos).
Um dos principais fatores a motivarem o desenvolvimento de sistemas peer-to-peer é o fato de que modelos cliente-servidor não costumam ser escaláveis, por dependerem de fatores como a capacidade de processamento e largura de banda de que dispõe o host que disponibiliza determinado serviço.

No modelo peer-to-peer, por outro lado, cada usuário disponibiliza os dados de que dispõe e seus recursos de hardware ao mesmo tempo que faz uso dos recursos dos outros usuários, o que faz com que os recursos disponibilizados cresçam na medida em que cresce o número de usuários do serviço.
Outra vantagem do paradigma peer-to-peer em relação ao cliente-servidor, é que como os recursos do sistema estão distribuídos entre os vários pares, seu funcionamento não depende de um servidor centralizado, cuja falha poderia comprometer o funcionamento de todo sistema.
Na prática, muitos sistemas distribuídos colaborativos utilizam uma solução híbrida de cliente-servidor e par-a-par para resolver o problema de inserir o usuário no sistema pela primeira vez. No caso das aplicações BitTorrent, o usuário precisa se comunicar com um servidor que mantém um registro dos pares que estão semeando ou “sugando” determinado arquivo (definirei melhor esses termos mais pra frente!) de modo a conseguir obter contato com seus primeiros “colaboradores”.
Visão geral do sistema Bittorrent
Como já sugeri anteriormente, os diversos agentes que operam para possibilitar o funcionamento de uma aplicação bittorrent formam um sistema. Nesse sistema, as aplicações bittorrent são as mais importantes. Elas servem para possibilitar o compartilhamento par-a-par de arquivos, geralmente grandes demais para serem obtidos via FTP ou HTTP de maneira prática.
Resumidamente, os arquivos a serem disponibilizados no sistema são divididos em blocos de tamanho fixo, e cada par pode descarregar esses blocos a partir de diferentes fontes, ao mesmo tempo, em qualquer ordem.
A aplicação de bittorrent é o que permite o download de arquivos através desse protocolo. Porém, como já disse, existem outros componentes essenciais para o funcionamento do sistema. Então, vamos dar uma olhada em cada um deles.
Arquivos torrent, trackers, seeders e leechers
Em primeiro lugar, para que um usuário seja capaz de encontrar um arquivo de seu interesse para baixar, ele precisa acessar algum site que possua links para arquivos do tipo .torrent. Esses arquivos .torrent, cuja estrutura analisaremos mais a frente, contém metadados sobre o arquivo em questão.
Uma das informações contidas nesse arquivo é o endereço do tracker, que é um servidor que realiza uma espécie de acompanhamento de quantos e quais pares possuem pedaços do arquivo.
Para começar a descarregar e compartilhar blocos de determinado arquivo, o usuário precisa, antes, contatar o tracker para se registrar como um integrante do torrent em questão e obter os endereços de um conjunto inicial de pares, com os quais ele tentará se conectar para se juntar ao sistema. Esse conjunto de pares enviado pelo tracker é aleatório, e, ao longo do tempo, alguns deles eventualmente irão se desconectar, enquanto outros pares que receberam o endereço do usuário em questão através do tracker, podem se conectar a ele, o que implica que o conjunto de pares conectados a qualquer usuário flutua ao longo do tempo.
Enquanto determinado par realiza o download de determinado arquivo, os blocos já descarregados são compartilhados com os outros pares do sistema. Quando um par conclui o download do arquivo, ele pode optar por (altruisticamente) continuar oferecendo seus blocos para outros pares que ainda não concluíram o download. Esses pares são denominados de seeders (semeadores). Já os pares que ainda não concluíram o download são chamados de leechers (sangue-sugas) (KUROSE; ROSS, 2017).
Para cada arquivo disponibilizado no sistema Torrent, o tracker, em conjunto com os usuários que já possuem o arquivo e estão compartilhando blocos do mesmo com outros usuários (seeders), e com os usuários que ainda não descarregaram o arquivo completamente e ainda dependem de outros pares, formam a torrente (torrent), ou enxame (swarm), daquele arquivo (COULOURIS et. al, p.907).
Política do “mais raro primeiro”
Uma vez de posse da lista de pares, o usuário então tenta estabelecer conexões com os mesmos, estabelecendo sua “vizinhança”. Os pares então trocam informações de que partes do arquivo eles possuem, e assim que um par descarrega um bloco com sucesso, ele envia uma mensagem para sua vizinhança informando que possui aquele bloco. De posse da lista de blocos que cada vizinho possui, o usuário pode enviar uma solicitação para receber um bloco de que precise. O protocolo Bittorrent implementa uma política de “mais raro primeiro” em relação aos blocos de dados, que funciona da seguinte maneira: ao receber a informação de que blocos seus vizinhos possuem, par verifica qual dos blocos é o mais raro (qual bloco é possuído pelo menor número de vizinhos), o que faz com que os blocos mais raros sejam repassados para o resto da rede, tornando-se mais disponíveis (KUROSE; ROSS, 2017, p. 174).
O algoritmo “tit-for-tat”
O que torna o BitTorrent um protocolo singular é o mecanismo utilizado para favorecer a cooperação entre pares, conhecido como tit-for-tat, que, nesse contexto, poderíamos traduzir para “toma lá, dá cá”. Quando um usuário está descarregando um arquivo, a cada dez segundos, a aplicação mede sua taxa de download em relação a cada par do qual está recebendo dados e seleciona os quatro pares com as taxas mais altas para então enviar dados para eles. O ato de enviar dados para um par do qual se está recebendo dados se chama “unchoking”, algo como “desobstruir”. Desse modo, pares com capacidade semelhante de transferência acabam colaborando entre si (KUROSE; ROSS, 2017, p. 174).
Além desses quatro pares, que podem mudar a cada 10 segundos, a aplicação também escolhe, a cada 30 segundos, um par ao acaso e envia blocos de dados para ele. Esse mecanismo se chama “optimistic unchoking” (desobstrução otimista), e tem dois efeitos: o primeiro é que o vizinho contemplado com a transferência de blocos pode vir a retribuir, enviando dados de volta para o par em questão, caso este se torne um de seus quatro transmissores com taxa mais alta. O segundo efeito é possibilitar que pares recém-chegados tenham acesso a blocos para começar a compartilhar (KUROSE; ROSS, 2017, p. 174).
Funcionamento do protocolo bittorrent
O protocolo BitTorrent e suas extensões são especificados em documentos denominados BitTorrent Enhancement Proposals, ou BEPs, que possuem papel semelhante aos da RFC para os protocolos de rede. O funcionamento básico do protocolo BitTorrent está especificado na BEP-0003, e o rascunho da segunda versão do protocolo se encontra na BEP-0052. A BEP-0003 define a maioria dos componentes do sistema que vimos anteriormente, como trackers, pares e arquivos .torrent, além de especificar o formato das mensagens utilizadas pelo protocolo. A seguir, abordaremos os aspectos mais importantes do protocolo BitTorrent tais como definidos pelas BEPs.
Arquivos torrent
Os metadados de um arquivo .torrent são codificados em um esquema denominado bencoding, que funciona da seguinte maneira:
- Strings são prefixadas com seu tamanho, seguido de : (dois pontos), seguido da sequência de caracteres que constitui essa string. Por exemplo, a palavra BitTorrent seria codificada como 10:BitTorrent.
- Inteiros são codificados como caracteres, entre o prefixo i e o sufixo e. Por exemplo, o número 150 seria codificado como i150e.
- Listas são codificadas com o prefixo l e o sufixo e, e seus elementos são separados por dois pontos. Por exemplo, a lista [Bit, Torrent] seria codificada como l3:Bit7:Torrente.
- Dicionários são codificados com o prefixo d e o sufixo e, e seus pares chave/valor são colocados em sequência. Por exemplo, o dicionário {‘Bit’:1, ‘Byte’: 8} seria codificado como d3:Biti1e4:Bytei8ee.
O arquivo .torrent possui um dicionário que armazena as informações relevantes sobre o arquivo compartilhado. A BEP-0003 prevê apenas duas entradas para o dicionário principal: a chave “announce”, cujo valor é o endereço do tracker que faz o acompanhamento do torrent, e a chave “info” que traz informações sobre o arquivo e sua divisão em blocos.
Entretanto, a BEP-0012 introduziu o conceito de múltiplos trackers, permitindo que o sistema lide melhor com a possibilidade de trackers desativados ou temporariamente inalcançáveis. Esses trackers são definidos na chave “announce-list” em forma de listas de listas.
Abaixo segue a parte inicial de um arquivo .torrent que contém informações sobre um determinado livro disponibilizado no sistema, em que podemos ver as chaves announce e announce-list:
d8:announce36:http://tracker.nwps.ws:6969/announce13:announce-listll36:http://tracker.nwps.ws:6969/announceel35:http://tracker.winglai.com/announceel37:http://fr33dom.h33t.com:3310/announceel38:http://exodus.desync.com:6969/announceel36:http://torrent.gresille.org/announceel38:http://tracker.trackerfix.com/announceel34:udp://tracker.btzoo.eu:80/announceel47:http://tracker.windsormetalbattery.com/announceel29:udp://10.rarbg.me:80/announceel39:udp://ipv4.tracker.harry.lu:80/announceel37:udp://tracker.ilibr.org:6969/announceel34:udp://tracker.zond.org:80/announceel38:http://torrent-tracker.ru/announce.phpel44:http://bigfoot1942.sektori.org:6969/announceel46:http://tracker.best-torrents.net:6969/announceel44:http://announce.torrentsmd.com:6969/announceel34:udp://tracker.token.ro:80/announceel25:udp://open.demonii.com:80el32:udp://tracker.coppersurfer.tk:80el40:http://tracker.thepiratebay.org/announceel31:udp://9.rarbg.com:2710/announceel36:udp://open.demonii.com:1337/announceel32:udp://tracker.ccc.de:80/announceel35:udp://tracker.istole.it:80/announceel38:udp://tracker.publicbt.com:80/announceel44:udp://tracker.openbittorrent.com:80/announceel35:udp://tracker.istole.it:80/announceel33:http://tracker.istole.it/announceel38:udp://tracker.publicbt.com:80/announceel36:http://tracker.publicbt.com/announceel43:udp://tracker.coppersurfer.tk:6969/announceel31:udp://bt.rghost.net:80/announceel36:udp://open.demonii.com:1337/announceel26:udp://pow7.com:80/announceee
Caso a aplicação tenha suporte a listas de trackers, a entrada “announce” é ignorada e apenas os trackers da lista são levados em consideração, por esse motivo, endereço de tracker contido em “announce” é o mesmo endereço contido no primeiro elemento de “announce-list”.
A chave info contém um dicionário com informações do arquivo a que o .torrent se refere. As chaves presentes costumam ser:
- name: nome do torrent
- piece length: o tamanho de cada bloco em que o arquivo é subdividido
- pieces: uma string contendo o hash SHA1 de cada bloco do arquivo
- length: tamanho do arquivo, caso o .torrent possua apenas um arquivo
- files: informações de cada arquivo do .torrent, caso este se refira a arquivos múltiplos
No fragmento abaixo, podemos observar o conteúdo da chave info do mesmo arquivo .torrent apresentado anteriormente:
infod5:filesld6:lengthi395989e4:pathl9:Cover.jpgeed6:lengthi1676870e4:pathl79:Debian 7- System Administration Best Practices - Rich Pinkall Pollei-signed.pdfeed6:lengthi2440e4:pathl12:Metadata.opfeee4:name67:Debian 7- System Administration Best Practices, 2013 [PDF]~StormRG~12:piece lengthi16384e6:pieces2540...
Tracker: solicitações e respostas
A solicitação ao tracker é feita através de um GET, pelo protocolo HTTP, no qual são embutidos os dados relevantes sobre o cliente com o formato: GET /announce? peer_id=????????& info_hash=??????& port=??????& left=????& downloaded=????& uploaded=?????&. Ou então via UDP, como descrito na BEP-0015.

O tracker então pode responder com uma mensagem de falha, ou então com uma mensagem em bencoding contendo um dicionário com a chave “interval”, cujo valor é o intervalo de tempo que o usuário deve esperar antes de enviar novas solicitações e um dicionário contendo as informações dos pares que estão carregando o download (peer id, ip e port).
Entretanto, a BEP-0023 especifica um modo compacto de resposta utilizado para diminuir o tamanho da mensagem, em que cada par é representado em apenas 6 bytes, sendo 4 bytes para o endereço em IPv4 e 2 bytes para a porta. Nesse caso, o peer id é suprimido. A redução no tamanho da mensagem costuma ser considerável, uma vez que em bencoding, apenas o fragmento 4:port:i0000e, por exemplo, já possuiria 13 bytes (um por caractere).
Magnet links
Apesar da implementação do recurso announce-list ter melhorado a questão da dependência de trackers, a dependência de servidores centralizados continua sendo um gargalo para o sistema BitTorrent. Uma solução encontrada foi a implementação dos magnet links, que fazem uso de uma DHT (Distributed Hash-table), que consiste em uma rede P2P paralela, utilizada para localizar pares que possuem determinado arquivo sem a necessidade de trackers. A especificação dessa DHT é apresentada na BEP-0005.
Um magnet link possui em sua estrutura a infohash de determinado torrent, isto é, o hash do conteúdo da chave info do arquivo .torrent tradicional. Esse código é utilizado para identificar o arquivo que se deseja descarregar, possibilitando a pesquisa na DHT dos endereços dos pares que possuem esse arquivo. Para conseguir participar da DHT, em primeiro lugar, a aplicação faz uso de endereços já fixados na própria aplicação e de endereços coletados de pares que participam do DHT, que foram encontrados previamente pelo cliente.
Opcionalmente, um magnet link pode conter endereços de trackers para que a aplicação busque pares do modo tradicional, explicado anteriormente. O uso de magnet links dispensa também a necessidade de obter o arquivo .torrent. Abaixo, temos o exemplo do link magnético de um torrent, contendo o infohash, o nome do arquivo e um a lista (opcional) de trackers:
magnet:?xt=urn:btih:93D066BC91D723C6E1F8BF70A7FB7DAAA398D645&dn=Networking+For+Beginners+The+Complete+Guide+To+Computer+Network&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.dler.org%3A6969%2Fannounce&tr=udp%3A%2F%2Fopentracker.i2p.rocks%3A6969%2Fannounce&tr=udp%3A%2F%2F47.ip-51-68-199.eu%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2920%2Fannounce&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.cyberia.is%3A6969%2Fannounce
Peer protocol
As mensagens enviadas entre os pares utilizam o peer protocol. Este protocolo geralmente opera sobre o TCP, porém, um outro protocolo denominado de uTP (uTorrent Transport Protocol) foi desenvolvido sobre o UDP para contornar alguns problemas ocasionados pela utilização do TCP, conforme especificado na BEP-0029.
Depois que dois pares realizam um handshake, segue-se um fluxo contínuo de mensagens entre os mesmos. As mensagens possuem um prefixo de 4 bytes (big endian) contendo seu tamanho. Depois segue-se 1 byte que define o tipo de mensagem, que pode ser:
- 0 – choke: avisa que nenhum dado será enviado até que o estado no par seja alterado para unchoke
- 1 – unchoke: avisa que o par está em estado “unchoke”, isto é, o emissor está disposto a enviar dados para o receptor da mensagem.
- 2 – interested: avisa que o par emissor tem interesse em receber dados.
- 3 – not interested: avisa que o par emissor não tem interesse em receber dados.
Esses quatro tipos de mensagem não possuem carga. Uma transmissão de dados pode ser iniciada assim que o par que deseja descarregar dados esteja interessado e o par que possui os dados tiver “desobstruído” o par em questão (leia-se, “aplicado unchoke”).
4 – have: contém o índice do pedaço que o usuário acabou de descarregar, essa mensagem é enviada para todos os seus pares.
5 – bitfield: contém um bitfield que representa os pedaços do arquivo que o par possui.
6 – request: solicita um pedaço do arquivo em questão para um par.
7 – piece: contém um pedaço do arquivo.
8 – cancel: solicita o cancelamento de um pedido feito através de uma mensagem de request. É utilizado num contexto bastante específico, conforme explicado na BEP-0003.
Concluindo…
Podemos dizer que o protocolo BitTorrent sobreviveu à prova do tempo, sendo utilizado ainda hoje, 20 anos após seu lançamento inicial. Unindo as vantagens do modelo peer-to-peer a mecanismos específicos do protocolo, o Bittorrent estimula a cooperação entre pares e oferece um serviço de download de arquivos de tamanho arbitrário robusto e resiliente. Além disso, podemos dizer que o protocolo está em constante evolução, já que as extensões do protocolo desenvolvidas ao longo do tempo e especificadas nas BEPs contornam problemas enfrentados anteriormente e otimizam a performance da aplicação, melhorando ainda mais a segurança, eficiência e experiência do usuário.
Referência bibliográfica
KUROSE, James F; ROSS, Keith, W. Chapter 2: Application Layer. in. Computer Networking: A Top-Down Approach. Pearson, 2012. p. 111 – 214.
TANEMBAUM, S. Andrew; STEEN, Maarten van. Chapter 2: Architecture. in. Distributed Systems. 3.ed. (Preliminary edition v. 3.01pre). p. 55 – 102. COULOURIS, et al. Distributed Systems: Concepts and Design. 5 ed. Addison Wesley, 2012.
BitTorrent Proposal Enhancements (Acessados em 24/11/2021):
BEP-0003 (The BitTorrent Protocol Specification)
BEP-0012 (Multitracker Metadata Extension)
BEP-0015 (UDP Tracker Protocol for BitTorrent)
BEP-0023 (Tracker Returns Compact Peer Lists)