Среда, 2024-04-17, 5:33 AM
Приветствую Вас Гость | RSS
Главная | Каталог статей | Регистрация | Вход
Пиринговые сети
Форма входа

Главное меню

Календарь

Друзья сайта
Программы
Блог KAD.DHT
Торренты eMule
Торрент трекер НТК
Компьютеры и сети
"25-й КАДР"

Рекламный блок


Статистика
Rambler's Top100 Адресная книга Интернет. Желтые страницы.

Рейтинг сайтов smarttop.info
Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » Статьи » Мои статьи

Спецификация протокола BitTorrent v 1.0 в деталях по русски
Идентификация
BitTorrent - это протокол для распространения файлов, основанный на принципе "точка-точка" и разработанный Брэмом Кохеном (Bram Cohen). Посетите его страницу по адресу bittorrent.com. BitTorrent разработан для облегчения передачи файлов множеству пиров по ненадежным сетям.

Цель

Цель этой спецификации состоит в том, чтобы задокументировать в деталях спецификацию протокола BitTorrent версии 1.0. Страница спецификации протокола Брэма ограничена основными понятиями, и теряет сопутствующие детали в некоторых областях. Я надеюсь, что этот документ будет написан в ясных и однозначных определениях, которые могут послужить основой для обсуждений и реализации в будущем.

Этот документ был создан для использования сообществом разработчиков BitTorrent. Каждый может внести изменения в этот документ, но только с пониманием того, что его содержание отражает текущую версию протокола, которая уже внедрена в целом ряде реализаций клиента.

Предметная область

Этот документ относится к первой версии (т.е. версии 1.0) спецификации протокола BitTorrent. На данный момент, он отражает файловую структуру торрентов, протокол обмена данными между пирами (peer wire), и спецификации HTTP/HTTPS-трекеров. При появлении новых версий этих протоколов, они должны быть специфицированы на своих отдельных страницах, но не здесь.

Условные обозначения

В этом документе используется ряд условных обозначений с целью представить информацию в кратком и однозначном виде.

Пир vs клиент: В этом документе пир - это любой ***клиент*** (это слово следует заменить адекватным синонимом) BitTorrent, участвующий в загрузке. Клиент - это тоже пир, однако это BitTorrent-клиент, запущеный на локальной машине. Читатели этой спецификации могут думать о нём как о клиенте, соединенным с некоторым числом пиров.

Кусок vs блок: В этом документе кусок относится к некоторой порции загруженных данных, которая описана в метафайле, и которая может быть проверена при помощи хеша SHA1. Блок - это порция данных, которую клиент может запросить у пира. Два или большее количество блоков составляют кусок, который затем может быть проверен.

Стандарт "де-факто": большие блоки текста курсивом описывают общепринятые подходы в различных реализациях BitTorrent-клиентов, ставшие стандартом "де-факто".

Bencoding

Bencoding - это способ определения и организации данных в сжатом формате. Он поддерживает следующие типы: байтовые строки (byte strings), целые числа(integers), списки(lists) и хэш-таблицы(dictionaries).

Байтовые строки

Байтовые строки кодируются следующим образом: <длина строки, кодируемая в десятичной ASCII, в которой есть только символы цифр>:<строковые данные>

Надо заметить, что здесь нет фиксированного начального и конечного разделителя.

Пример: 4:spam представляет строку "spam"

Целые числа

Целые числа кодируются следующим образом: i<целое число, закодированное в десятичной ASCII>e

Начальный символ i и конечный е - начальный и конечный разделители соответственно. Вы можете кодировать отрицательные числа, такие как i-3e. Целому числу не может предшествовать префикс, состоящий из нулей, как например i04e. Вместе с тем, i0e является является корректной записью нуля.

Пример: i3e представляет число "3"

ПРИМЕЧАНИЕ: Максимальное количество бит целого числа не специфицируется, но для рассмотрения "больших файлов" aka .torrent для более 4-х гигабайт необходимо знаковое 64-битное целое.

Списки

Списки кодируются следующим образом: le

Начальный символ l и конечный е - начальный и конечный разделители соответственно. Списки могут содержать bencode-кодированные значения любых типов, включая целые числа, строки, хэш-таблицы и другие списки.

Пример: l4:spam4:eggse представляет список из двух строк: [ "spam", "eggs" ]

Хэш таблицы

Хэш-таблицы кодируются следующим образом: de

Начальный символ d и конечный е - начальный и конечный разделители соответственно. Заметьте, что ключи должны быть bencode-кодированными строками. Значения хэш-таблицы могут быть bencode-кодированными значениями любого типа, включая целые числа, строки, списки и другие хэш-таблицы. Ключи могут быть только строковыми и должны фигурировать в отсортированном порядке (sorted as raw strings, not alphanumerics). Строки должны сравниваться с использованием бинарного сравнения, а не культурно-специфичного "естественного" сравнения.

Пример: 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" }

Реализации

Реализация на языке C:
http://funzix.svn.sourceforge.net/viewvc/funzix/trunk/bencode/bencode.c?view=markup

Реализация на языке Perl:
http://search.cpan.org/dist/Convert-Bencode/lib/Convert/Bencode.pm

Реализация на языке Java: http://www.koders.com/java/fid47111A56F2466C232E09AEF75A39915EC70D3536.aspx#L52

Python bdecode: decoding bencoded data with python - I've written this because bencode.py in the bittorrent source directory doesn't really handle nested bencoded data found in scrapes and this is on average 5-6 times faster than the perl implementation --Hackeron 08:56, 28 February 2007 (PST)

Структура файла мета-данных

Файл мета-данных закодирован в bencode-формате, подробное описание которого приведено выше.

Содержимое файла мета-данных (расширение файла — ".torrent") — это bencode-кодированная хэш-таблица, который содержит перечисленные ниже ключи. Все строковые величины закодированы в UTF-8.

info: Хэш-таблица, описывающая файл(ы) торрента. Есть две возможных формы: первая — для случая с 'одно-файловым' торрентом, без описания структуры директорий; вторая — для 'много-файлового' торрента (см. подробности далее).

announce: URL трекера для публикации торрента (строка).

announce-list: (опциональный) Это расширение к официальной спецификации с сохранением обратной совместимости. Ключ используется для реализации списка резервных трекеров. Полное описание можно найти здесь — http://home.elp.rr.com/tur/multitracker-spec.txt.

creation date: (опциональный) Дата создания торрента, в стандартном формате UNIX-времени (целое число секунд прошедших с 01 января 1970 00:00:00 по UTC).

comment: (опциональный) Текстовый комментарий в свободной форме от автора (строка).

created by: (опциональный) Имя и версия программы, которая использовалась для создания torrent-файла (строка).

Хэш-таблица "Info"

Этот раздел описывает общие поля и для "одно-файлового", и для "много-файлового" торрента.

piece length: Размер каждого куска в байтах (целое).

pieces: Строка, составленная объединением 20-байтовых значений SHA1-хэшей каждого куска (один кусок — один хэш) (байтовая строка).

private: (опциональный) Это поле является целым числом. Если оно установлено в значение "1", клиент ОБЯЗАН получать список пиров ТОЛЬКО с помощью трекеров, перечисленных в файле мета-данных. Если поле установлено в "0" или вообще отсутствует, клиент может получать список пиров другими способами, например с помощью PEX (обмен пирами) или DHT. Таким образом, слово "приватный" можно читать как "без внешних источников списка пиров".

ПРИМЕЧАНИЕ: Не все согласны с таким описанием. Вот например определение из вики клиента Azureus: http://www.azureuswiki.com/index.php/Secure_Torrents.

Кроме того, следует отметить, что даже если это поле и используется на практике, оно не является частью официальной спецификации.

Info в одно-файловом режиме

В случае одно-файлового режима, хэш-таблица info дополняется следующими ключами:

name: Имя файла, который содержит торрент. Носит рекомендательный характер. (строка)

length: Размер файла в байтах (целое).

md5sum: (опциональный) 32-символьная шестнадцатеричная строка соответствующая MD5-сумме файла. Она не используется в BitTorrent, но записывается в торрент некоторыми программами для лучшей совместимости.

Info в много-файловом режиме

В случае много-файлового режима, хэш-таблица info дополняется следующими ключами:

name: Имя корневой директории, которую содержит торрент. Носит рекомендательный характер. (строка)

files: Список из хэш-таблиц, по одной на каждый файл. Каждая хэш-таблицы в этом списке содержит следующие ключи:

length: Размер файла в байтах (целое).

md5sum: (опциональный) 32-символьная шестнадцатеричная строка соответствующая MD5-сумме файла. Она не используется в BitTorrent, но записывается в торрент некоторыми программами для лучшей совместимости.

path: Список, содержащий один или более строковых элементов, объединение которых даёт путь и имя файла. Каждый элемент в списке соответствует либо имени директории, либо (в случае с последнем элементом) — имени файла. Например, файл "dir1/dir2/file.ext" должен состоять из трёх строковых элементов: "dir1", "dir2" и "file.ext". Он кодируется как список из строк в bencode-формате вот так:
l4:dir14:dir28:file.exte

Примечания

Ключ 'piece length' устанавливает номинальный размер куска, который, как правило, кратен 2-м. Размер куска обычно выбирается исходя из общего количества файловых данных в торренте, учитывая то, что слишком большой размер куска неэффективен, а слишком маленький даёт в результате большой торрент файл. При выборе наименьшего размера куска руководствуйтесь здравым смыслом. Желательно не делать торрент-файл размером больше, чем 50-75КБ (чтобы облегчить его загрузку на сервер). Однако, сейчас, когда размеры хостинга и ширина каналов не сильно ограничиваются, лучший размер куска для более эффективной раздачи файлов равен 512КБ или меньше (по крайней мере для торрентов примерно до 8-10ГБ), даже если это приведёт к увеличению торрент-файла. Часто используемые размеры — 256КБ, 512КБ и 1МБ. Каждый кусок равен выбранному размеру, за исключением последнего, размер которого может быть меньше. Количество кусков вычисляется делением общего размера файлов торрента на размер куска и округляется в большую сторону. Для вычисления границ кусков в много-файловом торренте, файловые данные рассматриваются как один большой непрерывный поток, составленный объединением содержимого всех файлов в порядке их следования в списке 'files'. Число кусков и их границы определяются таким же образом, как и в случае одного файла. Куски могут перекрывать границы файлов (т.е. начало куска может находится в конце предыдущего файла, а конец — в начале следующего).

Каждый кусок имеет соответствующий ему SHA1-хэш. Для формирование значения ключа 'pieces' (см. описание хэш-таблицы 'info' выше) хэши всех кусков объкдиняются в одну строку (обратите внимание — в строку, а не в список). Её длина должна быть кратна 20-ти.

Протокол трекера (HTTP/HTTPS)

Трекер — это HTTP/HTTPS сервис, который отвечает на HTTP GET запросы. Запросы содержат в себя метрику от клиентов, помогающая трекеру вести статистику для торрента. В ответах содержится список пиров, чтобы клиент мог участвовать в раздаче. Базовый URL запроса состоит из 'announce URL', который определён в файле мета-данных (торрент-файл), и параметров, которые добавляются к этому URL'у при помощи стандартного CGI-метода (т.е. добавление '?' после announce-URL, за которым следует последовательности 'параметр=значение', разделённые символом '&').

Обратите внимание, что все бинарные данные в URL (в особенности info_hash и peer_id) должны быть правильно экранированы. Это означает, что любой байт, который не входит в множества ''0-9'', ''a-z'', ''A-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'а).

Сообщения

Все остальные сообщения в протоколе принимают форму . Длина префикса состоит из четырех байт big-endian значения. Идентификатор сообщения - это один десятичный символ. Полезная нагрузка (payload) непосредственно зависит от сообщения.

keep-alive:

keep-alive сообщения - это сообщения с нулевыми байтами, length prefix установлен в ноль. Не существует идентификатора сообщения и никакой полезной нагрузки сообщение не несёт. Пир может закрыть соединение, если он не получают никаких сообщений (keep-alive или любого другого сообщения) в течение определенного периода времени, поэтому keep-alive сообщение нацелено на поддержание связи. Это время, обычно равно двум минутам.

choke:

Choke-сообщение - это сообщение фиксированной длины без полезной нагрузки.

unchoke:

Unchoke-сообщение - это сообщение фиксированной длины без полезной нагрузки.

interested:

Interested-сообщение - это сообщение фиксированной длины без полезной нагрузки.

not interested:

Non interested-сообщение - это сообщение фиксированной длины без полезной нагрузки.

have:

Have-сообщение фиксированной длины. Полезная нагрузка - это с указвнием нулей (zero-based) индекс куска, который только что был успешно скачан и проверен с помощью хэша.

Конструкторское замечание: Это строгое определение, в реальности some games may be played. В частности, поскольку крайне маловероятно, чтобы пиры загружали куски, которые они уже имеют, пир может не рекламировать (advertise) наличие кусков пирам, которые эти куски имеют. Подавление HAVE-сообщений ("HAVE supression") как минимум приведет к 50% сокращению числа сообщений, а это сокращение примерно на 25-35% накладных расходов протокола (protocol overhead). В то же время, возможно целесообразно отправить HAVE-сообщение пирам, которые уже имеют этот кусок, поскольку он будет полезен в определении его редкости.

Вредоносные пиры также могут выбирать оглашение (advertise) имеющихся кусков, которые пир точно никогда не загрузит. Due to this attempting to model peers using this information is a bad idea

bitfield:

Bitfield сообщение может быть направлено сразу же после того, последовательность "рукопожатий" будет завершена, и до любых других сообщений. Оно является необязательным, и клиентам, не имеющих куски, нет нужды отсылать его.

Bitfield сообщение переменной длины, где X - это длина bitfield'a. Полезная нагрузка сообщения - bitfield представление кусков, которые были успешно загружены. Старший разряд в первом байте соответствует куску с индексом 0. Биты, которые пустые указывают пропавший кусок, а установленные биты обозначают валидные и доступные куски. Запасные биты в конце устанавливаются в ноль.

Bitfield неверной длины считается ошибочным. Клиенты должны разорвать соединение, если они получают bitfields неверного размера, или если bitfield имеет произвольный набор запасных битов.

request:

Сообщение-запрос фиксированной длины, используется для запросы блока. Полезная нагрузка сообщения содержит следующую информацию:

index: целое число, определяющее с указанием нулей (zero-based) индекс куска

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-байтовом значении, которое не было в действительности ни размером значения по

Категория: Мои статьи | Добавил: netnsk7072 (2011-02-11)
Просмотров: 4243 | Рейтинг: 5.0/3
Всего комментариев: 0

Copyright www.netnsk.ru © 2024
Сделать бесплатный сайт с uCoz