Спецификация протокола BitTorrent в подробностях
Содержание
Внимание!
Это перевод неофициальной документации первой версии пирингового протокола BitTorrent, запуск которой состоялся 2 июля 2001 года.
В настоящее время перевод проверяется и дополняется по состоянию исходника на 1 February 2017, at 08:39.
Определение
BitTórrent — это одноранговый протокол распространения файлов по принципу «точка-точка» (peer-to-peer), был создан Брэмом Коэном (Bram Cohen), написавшим первый torrent-клиент на языке Python 4 апреля 2001 года. Посетите его страницу по адресу www.bittorrent.com. BitTorrent разработан для упрощения передачи файлов на множество узлов в ненадежных сетях.
Цель
Целью данной спецификации является подробное документирование протокола BitTorrent версии 1.0. Страница Брэма спецификации протокола описывает только основные понятия, и в некоторых моментах описанию не хватает сопутствующих деталей. Есть надежда, что этот документ, написанный в ясных и однозначных определениях, станет официальной спецификацией, которая может послужить основой для обсуждения и реализации в будущем.
Этот документ был создан для использования сообществом разработчиков BitTorrent. Каждый может внести свой вклад, но только с пониманием, что содержание документа должно отражать текущую версию протокола, реализация которой уже внедрена в целом ряде клиентов.
Здесь не принимают запросы на объяснение новых особенностей. Для этого, пожалуйста, обратитесь к почтовой рассылке.
Область применения
Этот документ относится к первой версии 1.0 спецификации протокола BitTorrent. На данный момент он отражает файловую структуру торрентов, протоколу однорангового обмена (peer wire) и спецификации HTTP/HTTPS-трекеров. По мере выхода новых версий этих протоколов, они должны быть описаны на отдельных страницах, но не здесь.
Связанные документы
- Официальная спецификация протокола
- Список запросов пользователей и разработчиков
- Расширения протокола трекеров
Соглашения
В этом документе используется ряд условных обозначений с целью предоставить информацию в краткой и недвусмысленной форме.
peer v/s client: узлы и клиенты
Примечание переводчика
Википедия использует термин узел как синоним слова peer, хотя на самом деле, это точка подключения, он же клиент одноранговой сети, он же одноранговый клиент. Узлу более соответствует нода (noda). Впервые фраза «peer-to-peer» была использована в 1984 году при разработке архитектуры Advanced Peer to Peer Networking (APPN) фирмы IBM.
В этом документе пир — это любой участник одноранговой сети (клиент), разделяющий загрузку через BitTorrent с другими участниками. Клиент также является пиром, конечно, если это BitTorrent-клиент, запущенный на локальной машине. Читатели этой спецификации могут представлять себя как клиента, подключенного ко множеству пиров.
piece v/s block: фрагменты и блоки
В этом документе слово фрагмент относится к некоторой порции загруженных данных, которая описана в файле метаинформации и может быть проверена при помощи алгоритма хеширования SHA1. Слово блок относится к порции данных, которую клиент может запросить у пира. Два и более блоков составляют фрагмент, который затем может быть проверен.
Простыми словами
Суть BitTorrent состоит обмене блоками между пирами. Когда все блоки одного фрагмента загружены, этим фрагментом можно поделиться с другими пирами. Как только все фрагменты загружены, пир меняет статус с загружающего (leecher) на раздающего (seeder).
© из статьи Пишем свой BitTorrent-клиент
информация де-факто
Большие объемы текста в этом документе, выделенные курсивом, указывают на общепринятые подходы, настолько распространенные в различных клиентских реализациях BitTorrent, что де-факто считаются стандартом, хотя и не являются им.
В этом документе они будут на такой жёлтой плашке, или другим образом выделены.
Чтобы помочь другим читателям найти последние изменения, внесенные в этот документ, заполняйте поле «Summury:» при редактировании. Оно должно содержать краткую (т.е. однострочную) запись для каждого существенного изменения, которое вы внесли в документ. (Этот абзац относится к исходному документу в вики wiki.theory.org, здесь заполняйте, пожалуйста, коменнтарии к коммитам.)
Bencoding
Bencode
Бинарный формат описания, используемый системой BitTorrent для хранения и передачи свободно структурированных данных.
Включает четыре типа данных: строка байтов, целое число, список (массив), словарь (ассоциативный массив). Используется в файлах *.torrent, которые являются словарём в формате Bencode.
Произносится как Bee-encode биэнкод.
Bencoding — это способ определения и организации данных в сжатом формате. Он поддерживает следующие типы:
- байтовые строки (byte strings)
- целые числа (integers)
- списки (lists)
- хэш-таблицы (dictionaries)
Байтовые строки
Байтовые строки кодируются следующим образом:
<длина строки, кодируемая в десятичной ASCII, в которой есть только символы цифр>:<строковые данные>
Надо отметить, что у строк нет фиксированного начального и конечного разделителя.
Пример:
4:spam
представляет строку “spam”
Пример:
0:
представляет пустую строку “”
Целые числа
Целые числа кодируются следующим образом:
i<целое число, закодированное в десятичной ASCII>e
Начальный символ i
и конечный е
— начальный и конечный разделители, соответственно. Целому числу не может предшествовать префикс, состоящий из нулей, например, i03e
. Вместе с тем, i0e
является корректной записью нуля.
Пример:
i3e
представляет число 3
Пример:
i-3e
представляет отрицательное число -3
Пример:
i-0e
является ошибкой
ПРИМЕЧАНИЕ: Максимальное количество бит целого числа не описывается, но для рассмотрения больших файлов, таких как торренты размером более 4-х гигабайт, необходимо знаковое целое 64-битное поле.
Списки
Списки кодируются следующим образом:
l<bencode-закодированные значения>e
Начальный символ l
и конечный е
— начальный и конечный разделители, соответственно. Списки могут содержать bencode-кодированные значения любых типов, включая целые числа, строки, хэш-таблицы и другие списки.
Пример:
l4:spam4:eggse
представляет список из двух строк [ “spam”, “eggs” ]
Пример:
le
представляет пустой список []
Хэш-таблицы (словари)
Хэш-таблицы кодируются следующим образом:
d<bencode-кодированная строка-ключ><bencode-кодированный элемент>e
Начальный символ d
и конечный е
— начальный и конечный разделители, соответственно. Заметьте, что ключи должны быть bencode строками. Значения словаря могут быть любого bencode типа, включая целые числа, строки, списки и другие словари. Ключи должны быть только строковыми и представлены в отсортированном порядке общего вида (sorted as raw strings), но не алфавитно-цифровом. Ключи следует сортировать с использованием побайтового сравнения, а не «естественного» порядка сравнения, принятого в культуре вашего общества.
Пример:
d3:cow3:moo4:spam4:eggse
представляет собой хэш-таблицу { “cow” => “moo”, “spam” => “eggs” }
Пример:
d4:spaml1:a1:bee
представляет хэш-таблицу со списком { “spam” => [ “a”, “b” ] }
Пример:
d9:publisher3:bob17:publisher-webpage15:www.example.com18:publisher.location4:homee
представляет словарь{ "publisher" => "bob", "publisher-webpage" => "www.example.com", "publisher.location" => "home" }
Пример:
de
представляет пустой словарь {}
Известные реализации на разных языках программирования
- C, автор Mike Frysinger
- C
- C, автор Chul-Woong Yang
- C#, автор Søren Kruse
- C#, автор SuprDewd
- C#, автор LordMike
- Clojure, автор nakkaya
- Common Lisp, автор osa1
- Elixir, автор Rodney Folz
- Erlang
- Erlang, автор ladybug
- Go, автор Mark Samman
- Haskell, автор Edi
- Haskell, автор Mhitza
- Java, автор gyurix
- Java, автор Frazboyz
- JavaScript, автор Demon
- JavaScript\NodeJS, автор Ben Reinhart
- JScript, автор Sergej B.
- Objective-C, автор Chrome
- OCaml, автор MLDonkey
- Perl
- PHP
- PHP, автор Jesse Schalken
- PHP Extension, реализация на C++, автор Frederick Zhang
- Pixie
- Pony
- Prolog, автор mndrix
- Python, автор Hackeron
- Python, автор Markus Eliasson
- Scala, автор Andrea Fey
- Scheme, автор Mark Skilbeck
- VBScript, автор Demon
- Elixir, автор Patrick Gombert
- Ruby, автор Kasper Holbek Jensen
Структура файла метаинформации
Файл метаданных (metainfo file, расширение файла .torrent
) закодирован в формате bencode, подробное описание которого приведено выше.
Содержимое файла метаданных представляет собой словарь bencode, ключи которого перечислены далее; необязательные, опциональные поля помечены звездочкой *. Все строковые величины должны быть в кодировке UTF-8.
-
info
: Словарь описывает файл(ы) торрента. Есть две возможных формы: одна для случая с однофайловым торрентом, без описания структуры каталогов; другая для многофайлового торрента (подробности ниже) -
announce
: URL трекера для публикации торрента (строка) -
announce-list *
: Это расширение к официальной спецификации с сохранением обратной совместимости. Ключ используется для реализации списка резервных трекеров. Значение представляет собой список списков строк. Полное описание можно найти здесь: http://bittorrent.org/beps/bep_0012.html -
creation date *
: Дата создания торрента в стандартном формате UNIX-времени (unixtimestamp, целое число секунд, прошедших с 01.01.1970 00:00:00 UTC) -
comment *
: Комментарий в свободной форме (строка) -
created by *
: Название и версия программы, которая использовалась для создания torrent-файла (строка)
Хэш-таблица Info
общие поля для однофайлового и многофайлового режимов
-
piece length
: Размер каждого фрагмента (piece) в байтах (целое). -
pieces
: Строка, составленная объединением всех 20-байтовых значений SHA1-хэшей каждого фрагмента, одна хэш-строка на каждый фрагмент (байтовая строка, не urlencoded). -
private *
: Поле является целым числом. Если установлено значение1
, клиент ДОЛЖЕН обозначить свое присутствие, чтобы получать другие одноранговые узлы (список пиров) ТОЛЬКО через трекеры, явно прописанные в файле метаданных. Если поле установлено в значение0
или отсутствует, клиент может получать список пиров другими средствами, например, через обмен пирами PEX (Peering EXchange), или технологию DHT (Distributed Hash Table). Таким образом, название ключа «частный» можно понимать как «без внешних узлов».
ПРИМЕЧАНИЕ: Вокруг частных трекеров ведется много споров. Официальный запрос на изменение спецификации находится по адресу http://bittorrent.org/beps/bep_0027.html. Azureus был первым клиентом, который поддержал частные трекеры, прочтите вики проекта для получения подробной информации http://wiki.vuze.com/w/Private_torrent.
info в однофайловом режиме
В случае однофайлового режима (single-file mode) словарь info
дополняется следующими ключами:
-
name
: Имя файла, который находится в торренте. Носит рекомендательный характер (байтовая строка) -
length
: Размер файла в байтах (целое) -
md5sum *
: 32-символьная шестнадцатеричная строка, соответствующая MD5-сумме файла. Поле не используется в BitTorrent, но заполняется некоторыми программами для улучшения совместимости
info в многофайловом режиме
В случае многофайлового режима (multi-file mode), info
дополняется следующими ключами:
-
name
: Название каталога, который содержит все файлы. Носит рекомендательный характер (байтовая строка) -
files
: Список словарей с описанием каждого файла. Каждая хэш-таблица в этом списке содержит следующие ключи:-
length
: Размер файла в байтах (целое) -
md5sum *
: 32-символьная шестнадцатеричная строка, соответствующая MD5-сумме файла. Поле не используется в BitTorrent, но заполняется некоторыми программами для улучшения совместимости -
path
: Список из одного или более строковых элементов, объединение которых даёт путь и/или имя файла. Каждый элемент в списке соответствует либо названию каталога в пути к файлу, либо это имя файла, если элемент последний в списке.Пример: для файла
dirC/dirF/file.ext
это поле состоит из трёх строковых элементовdirC
,dirF
иfile.ext
и кодируется как список из строк в bencode-формате таким образом:l4:dirC4:dirF8:file.exte
, т.е.строка с пробелами для понимания: l 4: dirC 4: dirF 8: file.ext e
-
ПРИМЕЧАНИЯ:
- Поле
piece length
определяет номинальный размер фрагмента, который, как правило, является степенью двойки. Размер фрагмента обычно выбирается на основе общего объема файлов в торренте с учетом, что слишком большой размер фрагмента ведет к неэффективности, а слишком маленькие фрагменты раздувают размер торрент-файла. Исторически сложилось, что размер фрагмента выбирался таким, чтобы размер файла метаданных получался не больше, чем 50-75Кб (предположительно, чтобы снизить нагрузку на сервер с торрент-файлами).- В настоящее время лучшим размером фрагмента для наиболее эффективной раздачи считается 512Кб или меньше для торрентов около 8-10Гб, даже если это приведёт к большему размеру торрент-файла. Наиболее распространённые размеры фрагментов 256Кб, 512Кб и 1Мб.
- Каждый фрагмент имеет одинаковую длину, кроме последнего, размер которого может быть меньше. Количество фрагментов вычисляется делением общего размера файлов торрента на размер фрагмента и округляется в большую сторону
ceil( total_length / piece_size )
. - Для вычисления границ фрагментов в случае с несколькими файлами (многофайловый торрент) считайте файловые данные одним непрерывным потоком, состоящим из конкатенации содержимого каждого файла в порядке их следования в списке файлов (поле
files
). Затем, количество фрагментов и их границы определяются таким же образом, как и в случае с одним файлом. Фрагменты могут перекрывать границы файлов (т.е. начало фрагмента может находится в конце предыдущего файла, а конец — в начале следующего).
- Каждый фрагмент имеет соответствующий ему SHA1-хэш содержащихся в нём данных. Для формирования значения ключа
pieces
(см. описание хэш-таблицы info выше) хэши всех фрагментов объединяются в одну строку. Обратите внимание, что это одна строка, а не список, её длина должна быть кратна 20 (двадцати).
Протокол трекера (HTTP/HTTPS)
Трекер — это HTTP/HTTPS сервис, который отвечает на HTTP-запросы методом GET. Запросы содержат в себе метрики от клиентов, которые дают возможность трекеру вести общую статистику о конректном торренте. Ответ содержит список пиров, чтобы клиент мог участвовать в раздаче. Основной URL запроса состоит из аннонсированного адреса (announce URL), который определён в файле метаданных (торрент-файл), и параметров, которые добавляются к этому URL’у при помощи стандартного для CGI способа составить строку запроса: добавление ?
после announce-URL
, за которым следует одна или несколько пар ключ-значение key=value
, соединённые символом &
, т.е. в целом, это типичный query_string
.
Обратите внимание, что все бинарные данные в URL, особенно, info_hash
и peer_id
должны быть правильно экранированы. Это означает, что любой байт, который не входит в множество 0-9a-zA-Z$-_.+!*'()
, должен быть закодирован в формате %nn
, где nn
— шестнадцатеричное значение байта (подробнее в RFC 1738).
Пример: Для следующего 20-байтового хэша:
\x12\x34\x56\x78\x9a\xbc\xde\xf1\x23\x45\x67\x89\xab\xcd\xef\x12\x34\x56\x78\x9a
правильно закодированной является строка%124Vx%9A%BC%DE%F1%23Eg%89%AB%CD%EF%124Vx%9A
Параметры запроса к трекеру
Далее следует описание параметров, используемых в GET запросе от клиента к трекеру:
-
info_hash
: 20-байтовый SHA1-хеш от значения ключаinfo
файла метаданных, которое является хэш-таблицей (словарём) в формате bencode, описание поляinfo
было приведено ранее. -
peer_id
: 20-байтовая строка, которая используется как уникальный идентификатор клиента, сгенерированный им же при запуске. Значение может быть любым, в том числе и бинарным. На данный момент нет никаких рекомендаций по генерации этого идентификатора. Однако, справедливо предположить, что он должен быть уникальным для локальной машины. Таким образом, вероятно, следует включать в него такую информацию, как идентификатор процесса и, возможно, временную метку, записанную им при запуске. Способы кодирования этого поля основными клиентами описание ниже в разделе peer_id. -
port
: Номер порта, который прослушивает клиент. Стандартные порты, которые зарезервированы для BitTorrent: 6881-6889. Клиент может использовать любой другой порт, если не может открыть его в указанном диапазоне. -
uploaded
: Суммарное количество отданных данных (после того, как клиент послал событие ‘started’ трекеру) записанное десятичным числом. Пока это точно не определено в официальной спецификации, считается, что здесь должно быть общее число отданных байт. -
downloaded
: Суммарное количество скачанных данных (после того, как клиент послал событие ‘started’ трекеру) записанное десятичным числом. Пока это точно не определено в официальной спецификации, считается, что здесь должно быть общее число загруженных байт. -
left
: Число байт десятичным числом, которое клиент ещё должен скачать. -
compact
: Устанавленное значение1
указывает, что клиет может принимать компактные ответы. Список пиров заменяется строкой — по 6 байт на одного пира. Первые четыре байта — это хост (в сетевом порядке байтов), последние два байта — порт (опять же, в сетевом порядке байтов). Следует помнить, что некоторые трекеры поддерживают только компактные ответы (для экономии трафика) и игнорируют запросы без параметра “compact=1” или просто посылают компактный ответ, даже при “compact=0”. -
no_peer_id
: Говорит о том, что трекер может пренебречь полем ‘peer id’ в хэш-таблице ‘peers’. Этот параметр игнорируется, если включен компактный режим. -
event
: Значением может быть ‘started’, ‘completed’, ‘stopped’, либо пустое, что равнозначно неопределённому. Если параметр не определен, значит этот запрос выполняется через регулярные интервалы времени. Подробнее о значениях: -
started
: Первый запрос к трекеру обязательно должен быть с параметром “event=started”. -
stopped
: Должен быть послан трекеру, если клиент правильно завершает работу. -
completed
: Должен быть послан трекеру при завершении закачки. Однако это событие не должно посылаться, если при запуске клиента закачка уже на 100% завершена. По-видимому, это нужно для того, чтобы дать возможность трекеру правильно увеличивать показатель завершённых закачек, который зависит от этого события. -
ip *
: Реальный IP-адрес клиентской машины, формат адреса — четыре байта (десятичными числами) разделённых точками или шестнадцатеричный IPv6-адрес (RFC 3513). Примечание: Вообще, этот параметр не является необходимым, так как адрес клиента может быть взят из IP-адреса, с которого отправлен запрос. Параметр нужен только в случае, когда IP-адрес, с которого пришёл запрос, не является IP-адресом клиента. Это происходит, когда клиент соединяется с трекером через прокси-сервер. А также, это необходимо, когда клиент и трекер находятся в одной локальной части NAT-шлюза, т.к. иначе трекер будет выдавать внутренний (RFC 1918) адрес клиента, который не является маршрутизируемым. Поэтому, клиент должен однозначно установить IP-адрес (внешний, маршрутизируемый), для выдачи его внешним пирам. Разные трекеры обрабатывают этот параметр по-разному. Некоторые принимают его, если IP-адрес, с которого пришёл запрос, находится в диапазоне RFC 1918, другие — принимают безоговорочно, третьи — полностью его игнорируют. Если передан IPv6-адрес (например, 2001:db8:1:2::100), значит клиент может общаться только по протоколу IPv6. -
numwant *
: Количество пиров, которое клиент хочет получить от трекера. Значение может быть нулём. Если параметр не задан, по-умолчанию, обычно отдаётся 50 пиров. -
key *
: Дополнительная идентификация, которая не доступна остальным пользователям. Предназначена для того, чтобы клиент мог подтвердить свою подлинность при смене IP-адреса. -
trackerid
: Если предыдущий ответ содержал значение ‘tracker id’, это значение нужно вписать сюда.
Ответ трекера
Трекер отвечает текстом (text/plain), который содержит в себе хэш-таблицу в bencode-формате со следующими ключами:
-
failure reason
: Если присутствует, то является единственным ключом в хэш-таблице. Значение ключа — это текстовое сообщение об ошибке, сообщающее о том, почему запрос не удался (строка). -
warning message
: (новый, опциональный) Похож на ‘failure reason’, но ответ будет полным. Предупреждение отображается также, как и ошибка. -
interval
: Интервал в секундах, который клиент должен выдерживать между посылкой регулярных запросов трекеру. -
min interval
: Минимальный интервал для оповещений. Если задан, клиент не должен делать оповещения чаще, чем это значение. -
tracker id
: Строка, которую клиент должен посылать обратно в последующих оповещениях. Если предыдущее оповещение содержало ‘tracker id’, а в текущем ответе ключ отсутствует, используйте старое значение. -
complete
: Число пиров, имеющих все файлы торрента. Их называют сидерами (целое) -
incomplete
: Число пиров, не имеющих все файлы торрента. Их называют личерами (целое) -
peers
: (модель на хэш-таблицах) Значением является список, состоящий из хэш-таблиц, каждая из которых содержит следующие ключи: -
peer id
: Идентификатор пира для запросов трекеру, который он сам себе и выбрал. Был описан ранее (строка). -
ip
: IP-адрес пира в формате IPv6 или IPv4, либо DNS-имя (строка). -
port
: Порт пира (целое) -
peers
: (бинарная модель) Вместо использования хэш-таблиц, значением каждого элемента списка может быть строка, состоящая из 6 байт. Первые 4 байта — это IP-адрес; последние 2 байта — порт. Все байты записываются в сетевом порядке байтов (big endian нотация).
Как упоминалось ранее, список пиров, по-умолчанию, имеет 50 записей. Если торрент имеет небольшое количество пиров, список будет меньше. В противном случае, трекер выбирает пиры для списка случайным образом. Для осуществления выборки пиров для списка, трекер может использовать более интеллектуальный алгоритм. Например, не сообщать о имеющихся на раздаче сидерах другим сидерам.
Клиенты могут посылать запросы трекеру чаще, чем через указанный интервал: если произошло какое-либо событие (например, остановка (stopped) или завершение (completed) закачки), либо клиент хочет получить еще один список пиров. Тем не менее, постоянный опрос трекера (в оригинале, hammer — бить, наносить удары) для получения списков пиров — это плохо. Если клиент хочет получить список большего размера, ему следует использовать в запросе параметр ‘numwant’.
Примечание разработчика: Даже 30 пиров достаточно. На самом деле, официальный клиент 3-ей версии создает новые соединения, только если имеет менее 30 пиров, и отказывает в соединении, при более чем 55 пирах. Это значение имеет большое значение для производительности. Когда новый кусок полностью получен, большинству активных пиров должно быть послано HAVE-сообщение (см. ниже). В результате, количество трафика увеличивается пропорционально количеству пиров. Если их больше 25-ти, весьма маловероятно, что новые пиры поднимут скорость скачивания. Разработчикам клиентов настоятельно рекомендуется сделать так, чтобы этот параметр был незаметен и сложен для изменения, т.к. он будет полезен в редких случаях.
Метод scrape
Scrape — собирать, скрести, соскабливать. Большинство трекеров поддерживают другую форму запроса, которая используется для получения информации по определенному торренту (или всех торрентов), которыми управляет трекер. Вместо неудобного парсинга страницы со статистикой, клиент может отправить такой запрос, и трекер ответит так называемой scrape-страницей.
Для запроса scrape-страницы клиент использует HTTP GET метод, как у стандартного запроса описанного раннее, но по другому URL’у. Чтобы получить scrape-url, нужно проделать следующее. Ищем в announce-url последний символ ‘/’ (слэш). Если текст непосредственно следующий за ‘/’ не ‘announce’, это признак того, что трекер не поддерживает scrape. В противном случае, заменяем ‘announce’ на ‘scrape’.
Примеры: (announce-url -> scrape-url)
~http://example.com/announce -> ~http://example.com/scrape
~http://example.com/x/announce -> ~http://example.com/x/scrape
~http://example.com/announce.php -> ~http://example.com/scrape.php
~http://example.com/a -> (scrape не поддерживается)
~http://example.com/announce?x2%0644 -> ~http://example.com/scrape?x2%0644
~http://example.com/announce?x=2/4 -> (scrape не поддерживается)
~http://example.com/x%064announce -> (scrape не поддерживается)
Note especially that entity unquoting is not to be done. Этот стандарт задокументирован Bram’ом в списке рассылки BitTorrent development: http://groups.yahoo.com/group/BitTorrent/message/3275
Scrape-url может быть дополнен опциональным параметром ‘info_hash’ с 20-байтовым значением (см. выше). Это ограничит ответ трекера scrape-страницей, которая будет содержать информацию только о запрашиваемом торренте. В противном случае, статистика отдается по всем торрентам, которыми управляет трекер. Если это возможно, для уменьшения нагрузки на трекер и канал, использование параметра ‘info_hash’ строго рекомендуется.
Также, можно указать несколько параметров ‘info_hash’, если трекер это поддерживает. Пока это не является частью официальной спецификации, хотя уже стало стандартом де-факто. Пример:
http://example.com/scrape.php?info_hash=aaaaaaaaaaaaaaaaaaaa&info_hash=bbbbbbbbbbbbbbbbbbbb&info_hash=cccccccccccccccccccc
На scrape-запрос трекер отвечает текстовым документом (text/plain), иногда — сжатым по методу gzip, который содержит в себе хэш-таблицу в bencode-формате со следующими ключами:
files: Хэш-таблица, содержащая одну пару ключ/значение для каждого торрента, по которому есть статистика. Если задан валидный параметр ‘info_hash’, то таблица содержит одну пару ключ/значение. Каждый ключ — это 20-байтовое бинарное значение ‘info_hash’. Значение ключа — это еще одна хэш-таблица:
complete: Число пиров, имеющих все файлы торрента (сидеры) (целое)
downloaded: Общее количество завершенных закачек, зарегистрированных трекером (регистрируются при событии ‘event=complete’, то есть когда клиент закончил скачивание торрента)
incomplete: Число пиров, не имеющих все файлы торрента (личеры) (целое)
name: (опциональный) Внутреннее имя торрента, указанное в ключе ‘name’ раздела ‘info’ торрент-файла
Обратите внимание, что этот ответ имеет три уровня вложенных хэш-таблиц. Вот пример:
d5:filesd20:………………..d8:completei5e10:downloadedi50e10:incompletei10eeee
Где ……………….. — это 20-байтовое значение параметра ‘info_hash’ для торрента, со статистикой: 5 сидеров, 10 личеров и 50 завершенных закачек.
Неофициальные расширения к scrape
Ниже описаны ключи, которые могут использоваться в ответе, но их нет в официальной спецификации. Поэтому, пока они являются опциональными.
failure reason: Текстовое сообщение об ошибке, сообщающее о том, почему запрос не удался (строка). Клиенты, обрабатывающие этот ключ: Azureus.
flags: Хэш-таблица, содержащая разнообразные флаги. Значения флагов — это еще одна вложенная хэш-таблица, которая может содержать:
min_request_interval: Значение этого ключа — целое число, которое определяет, сколько секунд клиент должен ждать перед отправкой следующего scrape-запроса трекеру. Трекеры, посылающие этот ключ: BNBT. Клиенты, которые его обрабатывают: Azureus.
Протокол связи между пирами (TCP)
Обзор
Протокол связи между пирами (далее, просто peer-протокол) облегчает обмен кусками (pieces), перечисленных в торрент-файле.
Обратите внимание, что при описании peer-протокола в оригинальной спецификации используется термин “кусок”, однако это не тот “кусок”, который используется при описании торрент-файла. Поэтому, в этой спецификации будет использоваться термин “блок” для обозначения данных, которыми обмениваются пиры по сети.
Клиент должен поддерживать информацию о состоянии каждого соединения с удаленным пиром:
choked: Блокирует ли (от англ. choke — душить, пережимать) удаленный пир этого клиента или нет. Если пир блокирует клиента, это означает, что пир не будет отвечать на любой запрос клиента до тех пор, пока не разблокирует его. Клиенту не следует пытаться запрашивать блоки, т.к. все эти запросы будут проигнорированы.
interested: Заинтересован ли удаленный пир в чем-то, что может предложить клиент. Это означает, что удаленный пир начнет запрашивать блоки, когда клиент разблокирует его.
Обратите внимание, что сам клиент тоже следит и за тем, заинтересован ли он в пире (interested), а также, заблокирован ли пир клиентом или нет (choked/unchoked). Поэтому, реальный список выглядит примерно так:
am_choking: Клиент блокирует пира
am_interested: Клиент заинтересован в пире
peer_choking: Пир блокирует клиента
peer_interested: Пир заинтересован в клиенте
Клиент начинает соединие как “заблокированный” и “не заинтересованный”. Другими словами:
am_choking = 1
am_interested = 0
peer_choking = 1
peer_interested = 0
Блок скачивается клиентом тогда, когда он заинтересован в пире, а пир, в свою очередь, не блокирует клиента. Блок отдается клиентом тогда, когда он не блокирует пира, и пир заинтересован в клиенте.
Для клиента важно информировать пиры о том, заинтересован ли он в них или нет. Информацию об этом следует своевременно обновлять для каждого пира, даже если клиент им заблокирован. Это позволяет пирам знать, начнет ли клиент скачивание, когда он его разблокирует (и наоборот).
Типы данных
Если не указан другой способ, все целые числа в peer-протоколе кодируются как четырех байтовые значения в big-endian формате. В том числе и префиксный размер всех сообщений, которые приходят после установки связи.
Поток сообщений
Peer-протокол состоит из начальной установки связи (см. ниже) и последующего обмена сообщениями с префиксным размером (см. выше).
“Рукопожатие” (handshake)
“Рукопожатие” — это обязательное и первое в потоке сообщение, которое должен передать клиент. Его размер — это 49 байт + длина pstr (см. ниже).
handshake:
pstrlen: Длина строки
pstr: Строковый идентификатор протокола
reserved: Восемь зарезервированных байт. Все текущие реализации заполняют их нулями. Каждый бит в этих байтах может использоваться для изменения режима работы протокола. В своем email Брэм предлагает использовать младшие биты, чтобы старшие биты можно было использовать для изменения значения младших.
info_hash: 20-байтовый SHA1-хэш ключа ‘info’ торрент-файла. Это тот же ‘info_hash’, который передается в запросах трекеру.
peer_id: 20-байтовая строка, используется как уникальный идентификатор клиента. Это тот же ‘peer_id’, который передается в запросах трекеру (правда не всегда, например Azareus не передает при включенной опции анонимности).
Для протокола BitTorrent v1.0 данные такие: pstrlen = 19 и pstr = “BitTorrent protocol”.
Инициатор соединения немедленно посылает handshake-сообщение. Адресат может отложить ответ инициатору, если он обслуживает несколько торрентов одновременно (торренты однозначно идентифицируются по их ‘info_hash’). Несмотря на это, адресат должен ответить сразу, как только получит значение поля ‘info_hash’ в handshake-сообщении. Трекерная функция NAT-проверки не посылает поле ‘peer_id’ при рукопожатии.
Клиент должен оборвать соединение, если получил handshake-сообщение с ‘info_hash’ торрента, который он не обслуживает.
Если инициатор соединения получает handshake-сообщение, в котором ‘peer_id’ не совпадает с ожидаемым ‘peer_id’, то инициатор закрывает соединение. Обратите внимание, что инициатор, по-видимому, получает информацию о пире от трекера, которая включает в себя ‘peer_id’ этого пира. Поэтому, peer_id от трекера и peer_id при рукопожатии должны совпадать.
Идентификатор пира (peer_id)
peer_id должен быть длиной в 20 байт.
Есть два основных соглашения кодирования информации о клиенте и его версии в peer_id: Azareus-стиль и Shadow-стиль.
В Azareus-стиле используется следующее кодирование: ‘-‘; два символа для идентификатора клиента; четыре ASCII цифры для номера версии; ‘-‘; случайные числа.
Например: ‘-AZ2060-‘…
Известные клиенты, которые используют этот стиль кодирования:
Далее идет список ID для извеснных клиентов
Клиенты, которые встречаются в природе, но пока не идентифицированы:
‘BD’ (пример: -BD0300-)
‘NP’ (пример: -NP0201-)
‘wF’ (пример: -wF2200-)
‘hk’ (example: -hk0010-) Chinese IP address, unrequestedly sends info dict in message 0xA, reconnects immediately after being disconnected, reserved bytes = 01,01,01,01,00,00,02,01
В Shadow-стиле используется следующее кодирование: один альфа-цифровой ASCII символ, идентифицирующий клиента; до пяти символов для номера версии (разбивается с помощью ‘-‘, если больше пяти); три символа (обычно ‘—’, но не всегда); случайные символы. Каждый символ в строке с версией клиента обозначает число от 0 до 63: ‘0’=0, …, ‘9’=9, ‘A’=10, …, ‘Z’=35, ‘a’=36, …, ‘z’=61, ‘.’=62, ‘-‘=63.
Полное описание Shadow-стиля, включая информацию о существующих соглашениях, как кодировать версию тремя символами, можно найти здесь.
Например: ‘S58B—–‘… для клиента Shadow’s 5.8.11
Известные клиенты, которые используют этот стиль кодирования:
‘A’ - ABC
‘O’ - Osprey Permaseed
‘Q’ - BTQueue
‘R’ - Tribler
‘S’ - Shadow’s client
‘T’ - BitTornado
‘U’ - UPnP NAT Bit Torrent
Клиент Bram’а сейчас использует такой стиль… ‘M3-4-2—’ или ‘M4-20-8-‘.
BitComet делает нечто иное. Его peer_id состоит из четырех символов ASCII “exbc”, за которым следуют два байта X и Y, а затем случайные символы. X - десятичный (in decimal) номер версии до запятой, а Y - отвечает за два десятичных знака после запятой. BitLord использует ту же схему, но добавляет, “LORD” после байтов версии. Неофициальный патч для BitComet сменил “exbc” на “FUTB”. Кодирование идентификаторов пира в BitComet было приведено к стилю Azureus, как в BitComet версии 0,59.
XBT Client также имеет свой собственный стиль. Его peer_id состоит из трех заглавных символов “XBT” и затем следуют три ASCII цифры, представляющие номер версии. Если клиент является отладочной сборкой, седьмой байт - символ “d”, в противном случае это ‘-‘. После этого следует ‘-‘, а затем случайные цифры, заглавные и строчные буквы. Пример: “XBT054d-“ в начале будет означать отладочную сборку версии 0.5.4.
Opera 8 previews и Opera 9.x releases используют следующую схему peer_id: Первые два знака “OP”, а далее четыре цифры означают номер сборки. Все следующие символы - случайные шестнадцатиричные цифры в нижнем регистре.
MLdonkey использует следующую peer_id схему: первые символы - это “-ML”, далее разделённый точкой номер версии, затем “-“, и далее последовательность случайных символов. Например: ‘-ML2.7.2-kgjjfkd “
Bits on Wheels использует модель ‘-BOWxxx-yyyyyyyyyyyy’, где y - случайный символ (заглавная буква), а x зависит от версии. Версия 1.0.6 имеет XXX = A0C.
Queen Bee использует новый стиль Брама: “Q1-0-0 - ‘или’ Q1-10-0-“, а далее последовательность случайных байт.
BitTyrant является Azureus веткой, и просто использует “AZ2500BT ‘+ случайные байты, как peer ID в 1.1 версии. Заметьте: отсутствует тире.
TorrenTopia версия 1.90 претендует быть или есть производная от Mainline 3.4.6. Его peer ID начинается с ‘346 —— “.
BitSpirit имеет несколько режимов peer ID. В одном режиме он читает ID пиров и переконнекчивается, используя первые восемь байт в качестве основы для своих собственных ID. Его реальный ID отображается с использованием ‘\ 0 \ 3BS “(С нотации), как первые четыре байта для версии 3.x и’ \ 0 \ 2BS” - для версии 2.x. Во всех режимах ID конце может заканчиваться как “UDP0”.
Rufus использует свою версию в виде десятичных ASCII значений для первых двух байт. Третий и четвертый байты - “RS”. Затем следуют nickname пользователя и некоторые случайные байты.
В G3 Torrent ID начинается с ‘-G3’ и добавляется до 9 символов nickname пользователя.
FlashGet использует Azureus стиль с “PG”, но без замыкающего символа ‘-‘. Версия 1.82.1002 - по-прежнему использует цифры версии 1.82: “0180”.
BT Next Evolution происходит от BitTornado, но пытается имитировать стиль Azureus. Результатом является то, что его peer ID начинается с ‘-СВ “, по-прежнему с 4-значным номером версии, а затем продолжается тремя символами, которые описывают тип клиента в стиле Shad0w peer ID.
AllPeers принимает SHA1 хэш зависящий от пользователя и заменяет первые несколько знаков на “ЗС” + строка версии + “-“.
Многие клиенты используют все случайные числа, или 12 нулей после случайных чисел (например, старые версии клиента Bram’а).
Сообщения
Все остальные сообщения в протоколе принимают форму
keep-alive: <len=0000>
keep-alive сообщения - это сообщения с нулевыми байтами, length prefix установлен в ноль. Не существует идентификатора сообщения и никакой полезной нагрузки сообщение не несёт. Пир может закрыть соединение, если он не получают никаких сообщений (keep-alive или любого другого сообщения) в течение определенного периода времени, поэтому keep-alive сообщение нацелено на поддержание связи. Это время, обычно равно двум минутам.
choke: <len=0001><id=0>
Choke-сообщение - это сообщение фиксированной длины без полезной нагрузки.
unchoke: <len=0001><id=1>
Unchoke-сообщение - это сообщение фиксированной длины без полезной нагрузки.
interested: <len=0001><id=2>
Interested-сообщение - это сообщение фиксированной длины без полезной нагрузки.
not interested: <len=0001><id=3>
Non interested-сообщение - это сообщение фиксированной длины без полезной нагрузки.
have: <len=0005><id=4>
Have-сообщение фиксированной длины. Полезная нагрузка - это с указвнием нулей (zero-based) индекс куска, который только что был успешно скачан и проверен с помощью хэша.
Конструкторское замечание: Это строгое определение, в реальности some games may be played. В частности, поскольку крайне маловероятно, чтобы пиры загружали куски, которые они уже имеют, пир может не рекламировать (advertise) наличие кусков пирам, которые эти куски имеют. Подавление HAVE-сообщений (“HAVE supression”) как минимум приведет к 50% сокращению числа сообщений, а это сокращение примерно на 25-35% накладных расходов протокола (protocol overhead). В то же время, возможно целесообразно отправить HAVE-сообщение пирам, которые уже имеют этот кусок, поскольку он будет полезен в определении его редкости.
Вредоносные пиры также могут рекламировать обладание кусками, которые пир точно никогда не загрузит. В связи с этим попытки to model peers с помощью этой информации плохая идея
bitfield: <len=0001+X><id=5>
Bitfield сообщение может быть направлено сразу же после того, последовательность “рукопожатий” будет завершена, и до любых других сообщений. Оно является необязательным, и клиентам, не имеющих куски, нет нужды отсылать его.
Bitfield сообщение переменной длины, где X - это длина bitfield’a. Полезная нагрузка сообщения - bitfield представление кусков, которые были успешно загружены. Старший разряд в первом байте соответствует куску с индексом 0. Биты, которые пустые указывают пропавший кусок, а установленные биты обозначают валидные и доступные куски. Запасные биты в конце устанавливаются в ноль.
Bitfield неверной длины считается ошибочным. Клиенты должны разорвать соединение, если они получают bitfields неверного размера, или если bitfield имеет произвольный набор запасных битов.
request: <len=0013><id=6>
Сообщение-запрос фиксированной длины, используется для запроса блока. Полезная нагрузка сообщения содержит следующую информацию:
index: целое число, определяющее индекс куска начиная с нуля
begin: целое число от нуля, определяющее смещение в байтах запрашиваемого блока от начала куска
length: целое число, длина запрашиваемого блока
This section is under dispute! Please use the discussion page to resolve this!
View #1. Согласно официальной спецификациям, “Все текущие реализаций используют 2^15 (32KB) куски, и закрывают соединения, которые запрашивают количество данных более 2^17 (128Kb).” Уже в версии 3 или 2004, это поведение было изменено на использование 2^14 (16Кб) блоков. Начиная с версии 4.0 или mid-2005, соединение в Mainline при запросах больше, чем 2^14 (16Кб), и некоторые клиенты последовали этому примеру. Помните, что block-запросы меньше, чем куски (>= 2^18 байт), поэтому будут необходимы многочисленные запросы, чтобы скачать весь кусок.
Собственно, спецификация позволяет 2^15 (32Кб) запросы. Реальность такова, что все клиенты начиная с сегодняшнего момента будут использовать 2 ^ 14 (16Кб) запросы. Из-за клиентов, которые привязаны к такому размеру запросов, рекомендуется реализовывать программы, делающие запросы именно такого размера. Меньшие размеры запросов приводят к повышению накладных расходов в связи с увеличением количества требуемых запросов, проектировщики советуют не делать размер запросов меньше, чем 2 ^ 14 (16Кб).
Выбор предельного размера запрашиваемого блока не очень ясен. Mainline версии 4 осуществляет 16Кб-ые запросы, большинство клиентов будут использовать этот размер. В то же время размер 2^14 (16Кб) представляется полу-официальным (наполовину официальным, потому что официальная документация протокола не обновлялась) , поэтому, по сути, неправильным (не соответствующим спецификации). В то же время, разрешение бо’льших запросов расширяет набор возможных пиров, и при исключении очень низкой пропускной способности соединения (<256кб/сек), несколько блоков будет загружено в один choke-timeperiod, таким образом простое предписание старого предела размера блока вызывает минимальное ухудшение работы. Из-за этого фактора, рекомендуется только старое 2^17 (128 КБ) максимальное ограничение размера.
View #2. Текущая версия имеет по крайней мере следующие ошибки: Mainline начали использовать 2^14 (16384) байт запросы, когда он был единственным из существующих клиентов, только “официальная спецификация” все ещё говорила об устаревшем 32768-байтовом значении, которое не было в действительности ни размером значения по умолчанию, ни позволенным максимумом. В версии 4 поведение запросов не изменилось, но максимально допустимый размер запроса стал равным значению размера по умолчанию. В последней версии Mainline максимум изменился до 32768 (заметьте, что это первое появление 32768 либо для значения по умолчанию, либо для максимального размера запроса с момента появления первой версии). Утверждение: “большинство старых клиентов используют 32KB запросы” - является ложным. Обсуждение запросов не принимает последствия латентности во внимание.
piece: <len=0009+X><id=7>
Piece-сообщение переменной длины, где X - длина блока. Полезная нагрузка сообщения содержит следующую информацию:
index: целое число от нуля, определяющее индекс куска
begin: целое число от нуля, определяющее смещение блока внутри куска
block: блок данных, являющийся часть куска определенным параметром index
cancel: <len=0013><id <= 8>
Cancel-сообщение фиксированной длины, используется для отмены запросов блоков. Полезная нагрузка сообщения идентична той, которая была в “сообщении-запросе” (“request” message). Сообщение обычно используется во время стратегии “Конца игры” (End game, см. ниже раздел Алгоритмы).
port: <len=0003><id=9>
Port-сообщение отсылается посредством новых версий Mainline, которая реализует DHT Tracker. Порт для прослушивания является портом который DHT узел прослушивает. Этот пир должен быть вставлен в локальную таблицу маршрутизации (если DHT Tracker поддерживается).
Алгоритмы
Очереди
This section is under dispute! Please use the discussion page to resolve this!
View #1. Вообще пирам рекомендуется держать несколько невыполненных запросов для каждого соединения. Иначе полное круговое обращение сообщения (туда-обратно, round trip, RT) потребует загрузить блок до загрузки нового блока (круговое обращение PIECE-сообщения, и далее REQUEST-сообщения). В связи с высоким BDP (результат задержки полосы пропускания, высокой латентности или high bandwidth), это может привести к существенной потере эффективности.
Конструкторское замечание: Это наиболее важный показатель производительности. Статическая очередь из 10 заявок является приемлемой для 16Кб-ых блоков при связи 5 мБ/сек с латентности 5 мс. Становится очень распространённой связь с большей пропускной способностью, так это подталкивает проектировщиков интерфейсов предвидеть возможность изменений. Notably cable modems were known for traffic policing and increasing this might of aleviated some of the problems caused by this.
View #2. Примечание: большая часть информации в разделе “Очереди” является ложной или вводящей в заблуждение. Просто к сведению, что “установки по умолчанию для 5 исходящих запросов” не могут быть верными в течении долгого времени, “32 KB блоки” - являются ошибочными, поскольку вы, как правило, не используете 32 КБ блоки, и настраиваете длину очереди, изменив этот параметр (видимо размер блока) и пытаетесь измерить эффект, это плохая идея.
Супер-сидирование
(Это не является частью оригинальной спецификации)
Свойство супер сид (super-seed) в и над S-5.5 является новым алгоритмом сидирования, спроектированным для помощи инициатору торрента с ограниченной пропускной способностью “накачивать” большой торрент, уменьшая количество объема данных, необходимых для выгрузки (upload) и для порождения новых сидов в торренте.
Когда клиент-сид переходит в режим “супер-сид” , он не будет выступать в качестве стандартного сида, но маскируется как обычный клиент без каких-либо данных. Как только клиенты подключатся к нему, он будет информировать их о том, что он получил кусок - кусок, который никогда посылал, или, если все куски уже послал, он является очень редким. Это побудит клиента к попытке скачать только этот кусок.
Когда клиент закончил загрузку куска, сид не будет информировать его о любых других кусках до тех пор, пока он видит эти куски отосланные ранее, по крайней мере у одного другого клиента. До тех пор, клиент не будет иметь доступ к любым другим кускам, и поэтому не будет тратиться пропускная способность сида.
Этот метод привел к намного более высокой эффективности сидирования, посредством принуждения пиров в получении только редчайших данных, это и сокращение избыточного количества посылаемых данных, и ограничение объема данных, посылаемых пирам, которые не способствуют распространению этих данных в рое. До этого, сид должен был выгрузить от 150% до 200% от общего размера торрента перед тем как другие клиенты становятся сидами. Однако, большой торрент , раздаваемый в режиме ‘супер сид’ в состоянии набрать первых сидов уже после выгрузки 105% данных. Это намного эффективнее, чем при использовании стандартного режима.
Режим ‘супер-сид’ не рекомендуется для повсеместного использования. Хотя он помогает в распространении больших редких данных, поскольку он ограничивает выбор кусков, которые клиент может загружать, он также ограничивает возможности этих клиентов, в плане загрузки данных для уже частично полученных кусков<с данного="" сида=""> . Таким образом, супер-сид режим рекомендуется только для инициирующих сидирование серверов.с>
Почему бы далее не переименовать этот режим в”Initial Seeding Mode” или в “Releaser Mode”?
Стратегия загрузки кусков
Клиенты могут выбирать для загрузки куски в случайном порядке
Лучшая стратегия заключается в том, чтобы загружать редчайшие куски в первую очередь. Клиент может определить их посредством хранения первоначального bitfield каждого пира и последующих их обновлений при получении have-сообщений. Затем клиент может скачать куски, встречающиеся с минимальной частотой в bitfield’ах пиров. Заметьте, что любая стратегия определения наиболее редкого куска (Rarest First стратегия) должна включать элемент случайного выбора из, по крайней мере, несколких наиболее редких кусков, так как одновременная попытка многих клиентов перейти к одному и тому же “самому редкому” куску является непродуктивной.
Конец игры (End game)
Когда загрузка почти завершена, присутствует тенденция медленной закачки последних нескольких блоков. Для ускорения этой операции, клиент посылает запросы о всех своих потерянных блоках всем своим пирам. Чтобы это не стало ужасно неэффективно, при скачке требуемого блока клиент посылает cancel-сообщение всем остальным пирам.
Существуют не документированые пороговые значения, рекомендованные проценты, или количество блоков, которые должны использоваться как ориентир или общепринятые нормы
Когда переходить к стратегии “Конец игры” - вопрос спорный и требует обсуждения. Некоторые клиенты переходят к стратегии “Конец игры”, когда все куски были запрошены. Другие ждут до тех пор, пока оставшихся блоков станет меньше, чем запрошенных, и не более чем 20. Идея сохранить количество незаконченных блоков до 1 или 2 блоков представляется хорошей для минимизации накладных расходов, и если вы случайным образом запрашиваете блоки, то имеете низкие шансы скачать дубликаты. Подробнее о протокольных затратах (protocol overhead), можно прочитать здесь: http://hal.inria.fr/inria-00000156/en
Блокировка(Choking) и оптимистичная разблокировка (Optimistic Unchoking)
Блокировка (Choking) происходит по нескольким причинам. Протокол TCP ведет себя очень плохо когда одновременно происходит отсылка через несколько соединений. Кроме того блокировка позволяет каждому пиру использовать алгоритм “зуб за зуб”-ish (tit-for-tat-ish) для получения состоятельной скорости закачки.
Описанный ниже алгоритм блокировок применяется на настоящий момент. Крайне важно, чтобы все последующие алгоритмы одинаково хорошо работали как в сетях использующих только их, так и в сетях использующих текущий алгоритм.
Есть несколько критериев хорошего алгоритма блокировки, которым он должен удовлетворять. Он должен ограничить число одновременных отдач для хорошей производительности TCP. Алгоритм должен позволять избежать частого чередования блокировки и разблокировки, такой механизм известен как “фибриляция”. Алгоритм предполагает “вознаграждение” пирам, которые позволяют <клиенту> скачивать. Наконец, алгоритм должен периодически испытывать неиспользуемые соединения, чтобы проверить лучше они используемых в настоящее время или нет, такой механизм называется оптимистичной разблокировкой (optimistic unchoking).клиенту>
Текущий алгоритм блокировки избегает фибрилляции блокируя пиров не чаще чем раз в 10 секунд.
Взаимный обмен и заполнение канала отдачи управляется с помощью разблокирования четырех заинтересованных пиров, которые имеют лучший уровень отдачи. Это максимизирует скорость загрузки клиента. Эти четыре пира называются качающими, потому что они заинтересованы в загрузке данных с клиента.
Если пиры имеющие лучшую скорость отдачи (по сравнению с качающими), но не заинтересованные в разблокировании, становится заинтересованными, то пиры с худшей скоростью отдачи отключаются. Если клиент имеет полный файл, то решение о разблокировании пиров основывается на их скорости загрузки
При оптимистичном разблокировании в любой момент времени существует один разблокированный пир, независимо от его скорости отдачи (если заинтересован, он считается одним из четырех разрешенных качающих). Этот пир выбирается каждые 30 секунд. У новых пиров в трое выше шанс быть разблокированными чем у других. Это дает им неплохой шанс получить полный кусок для загрузки.
Анти-застопоривание (anti-snubbing)
Иногда пир может быть заблокирован всеми узлами с которых он качал. В таких случаях обычно он продолжает закачку с очень медленной скоростью, пока с помощью оптимистичного разблокирования не найдет лучших пиров. To mitigate this problem, when over a minute goes by without getting any piece data while downloading from a peer, BitTorrent assumes it is “snubbed” by that peer and doesn’t upload to it except as an optimistic unchoke. Это часто приводит к более чем одному оптимистичному разблокированию(за исключением единственного правила оптимистичного разблокирования описанного выше), что позволяет восстановить скорость загрузки гораздо быстрее.
Официальные расширения протокола
На текущий момент имеется несколько официальных расширений протокола.
Расширения “Fast Peers”
Зарезервированный бит: третий бит в 8-ом защищённом байте (reserved byte), т.е. reserved [7] |= 0x04
Расширения служат множеству целей. Они позволяют пиру быстрей присоединиться к рою давая ему специфические наборы кусков которые он может загрузить не обращая внимания на заблокированный статус. Они снижают накладные расходы протокола с помощью сообщений HaveAll и HaveNone и позволяют явно отказаться от запросов, тогда как ранее неявные отказы могли привести к тому, что пир ждет кусок который никогда не будет доставлен.
Спецификация документирована на сайте BitTorrent здесь: http://bittorrent.org/beps/bep_0006.html
Распределённые хэш-таблицы (Distributed Hash Table)
Зарезервированный бит: последний бит в 8-ом защищённом байте (reserved byte), т.е. reserved[7] | = 0x01 |
Это расширение позволяет пирам работать без использования стандартного трекера. Пир, реализующий этот протокол, сам становится “трекером” и хранит списки других узлов/пиров, которые могут использоваться для нахождения новых пиров.
Спецификация документирована на сайте BitTorrent здесь: http://bittorrent.org/beps/bep_0005.html
Шифрование соединения
Это расширение позволяет создавать зашифрованные соединения между пирами. Это может помочь обойти ограничения, которые накладывают некоторые провайдеры интернета на BitTorrent-трафик.
Спецификация описана в Wiki проекта Azureus: http://www.azureuswiki.com/index.php/Message_Stream_Encryption
Документация является достаточно полной, однако нужно уточнить пару моментов относительно шифрованных соединений: когда они должны приниматься и откат к обычным соединениям в случае неудачи при установлении шифрованных соединений.
Неофициальные расширения протокола
Протокол сообщений Azureus
Зарезервированный бит: 1
A protocol in its own right - if two clients indicate they support the protocol, then they should switch over to using it. It allows normal BitTorrent as well extension messages to be sent over it, and is documented here. Currently implemented by Azureus and Transmission.
It is not possible to use both this protocol and the LibTorrent extension protocol at the same time - if both clients indicate they support both, then they should follow the semantics defined by the Extension Negotiation Protocol.
WebSeeding
Возможность раздавать торрент через веб-сервер обычно называется WebSeeding. Она позволяет HTTP-серверу выступать в роли пира в BitTorrent сети.
There are at least two specification for how to combine a torrent download with a HTTP download. The first standard, implemented by BitTornado is quite easy to implement in the client, but is intrusive on the HTTP in that it requires a script handling requests on the server side. i.e. A plain HTTP server that just serves plain files isn’t enough. The benfits is that the script can be more abuse resistant. This specification is found here: http://bittornado.com/docs/webseed-spec.txt
The second specification requires slightly more from the client, but downloads from plain HTTP servers. It is specified here: http://www.getright.com/seedtorrent.html. It has been implemented by GetRight, libtorrent and Mainline.
Протокол расширений
Зарезервированный бит: 44, четвертый наиболее значимый бит в 6-ом зарезервированном байте, т.е. reserved[5] | = 0x10 |
This is a protocol for exchanging extension information and was derived from an early version of azureus’ extension protocol. It adds one message for exchanging arbitrary handshake information including defined extension messages, mapping extensions to specific message IDs. It is documented here: http://www.libtorrent.org/extension_protocol.html and is implemented by libtorrent, uTorrent and Mainline.
It is not possible to use both this protocol and the Azureus Messaging Protocol at the same time - if both clients indicate they support both, then they should follow the semantics defined by the Extension Negotiation Protocol.
Расширение протокола переговоров
Зарезервированные биты: 47 и 48
Эти биты позволяют клиенту поддерживающему одновременно “Azureus Messaging Protocol” и “LibTorrent’s extension protocol” решить какой именно из них следует использовать при общении и определяются здесь
BitTorrent Location-aware Protocol 1.0
Зарезервированный бит: 21
Протокол, учитывающий местоположение пира (в географическом смысле), для лучшей производительности. Спецификация может быть найдена здесь — http://wiki.theory.org/BitTorrent_Location-aware_Protocol_1.0_Specification
Расширенный SimpleBT протокол
Reserved Bits: fist reserved byte = 0x01, following bytes may need to be set to zero
An extension using message id 9 to add peer exchange and connection statistics exchange. The specification can be found here. The extension was in use in SimpleBT 0.32 to 0.36.1. Later versions of SimpleBT were called BitComet and used the similar but incompatible BitComet Extension Protocol.
Расширенный BitComet протокол
Reserved Bits: first two reserved bytes = “ex”
Не представлено никакой официальной документации.
In this protocol a peer announces the supported extensions by sending a message <len=0001+X><id=0xA0><extension 1>…
Extensions currently in use (TODO: reverse engineer semantics):
0xA0 (EXT_SUPPORT) see above, needs to be included in its parameter list
0xA1 (EXT_PEERREQ) ask for peer exchange, used in conjunction with EXT_PEERS
0xA2 (EXT_PEERS) in reply to EXT_PEERREQ and for updates afterwards
0xA3 (EXT_AUTH_SEED) appeared in BitComet 0.53, used in conjunction with EXT_AUTH_CRYPTOED
0xA4 (EXT_AUTH_CRYPTOED)
0xA5 (EXT_CONNGRANT) appeared in BitComet 0.48, used in conjunction with EXT_CONNACCEPT
0xA6 (EXT_CONNACCEPT)
0x06 (?) announced by BitSpirit instead of EXT_CONNACCEPT
0xA7 (EXT_CHAT_MESSAGE) appeared in BitComet 0.53, vanished in 0.71
0xA9 (EXT_HASH_REQ) appeared in BitComet 0.54, vanished in 0.71, used in conjunction with EXT_HASH
0xAA (EXT_HASH)
0xAB (EXT_REPORT_RATE_old) appeared in BitComet 0.54, was replaced by EXT_REPORT_RATE_new in 0.57
0xAC (EXT_REPORT_INFO) appeared in BitComet 0.54, vanished in 0.71, reappeared in 0.82
0xAD (EXT_REPORT_RATE_new) appeared in BitComet 0.57, vanished in 0.75, reappeared in 0.82
0xAE (EXT_BC_PASSPORT) appeared in BitComet 0.75
0xAF (EXT_DHE_PREFERRED) appeared in BitComet 0.75
0xB0 (?) appeared in BitComet 0.86
0xC0 (?) does not correspond to a message id, appeared in BitComet 0.49
A minimum implementation needs only accept EXT_SUPPORT, but EXT_PEERREQ and EXT_PEERS are supported by all known implementations.
Зарезервированные байты
Для упрощения идентификации в следующей таблице зарезервированные биты нумеруются от 1 до 64. Бит 1 - старший бит в первом зарезервированном байте. Бит 8 - младший бит в первом байте т.е byte[0] |= 0x01.. Бит 64 - младший бит в последнем байте т.е byte[7] |= 0x01.
An orange bit is a known unofficial extension, a red bit is an unknown unofficial extension.
- Таблица, в которая показывает расширения протокола, биты, зарезервированные для них, и поддержку данных расширений в различных BitTorrent клиентах *