# BitTorrent: участники, метаданные и проверка данных В предыдущих опытах мы искали адрес сервиса. Теперь задача другая: найти участников, у которых есть нужный файл, и проверить полученные от них данные. В BitTorrent участники раздачи называются **пирами**, а участник с полным файлом — **сидом**. **Трекер** сообщает клиенту контакты пиров. Сам файл передаётся между участниками. Все команды выполняются из каталога `seminar`; [подготовка стенда](../readme.md#самостоятельный-запуск-опытов). Файлы и участники в опытах создаются локально. ## 1. Прочитать метаданные и проверить части Файл `.torrent` описывает раздачу: содержит адрес трекера, сведения о содержимом и хеши частей. Рассматриваем формат BitTorrent v1 и раздачу одного файла. **Перед запуском предскажите:** 1. Изменится ли infohash (идентификатор раздачи), если заменить только адрес трекера или комментарий в `.torrent`? 2. Что обнаружит проверка, если изменить один байт второй части полученного файла? ~~~powershell docker compose run --rm -T tools python3 bittorrent/metadata.py demo --directory /work/metadata ~~~ Скрипт создаёт файл размером 256 KiB и метаданные с частями по 64 KiB, затем выполняет обе проверки. В выводе найдите: | Поле | Смысл | | --- | --- | | `announce` | Адрес трекера | | `name`, `length` | Имя файла и размер в байтах | | `piece length` | Размер части | | `pieces` | Хеши частей для проверки полученных данных | Сведения о файле и частях находятся в словаре `info`. В v1 **infohash вычисляется как SHA-1 от исходных байтов этого словаря**, записанного в формате bencode — формате сериализации метаданных BitTorrent. Адрес трекера и комментарий находятся вне `info`, поэтому их замена сохраняет infohash, если байты `info` не менялись. Для проверки файла каждая часть хешируется и сравнивается с соответствующим значением из `pieces`. В нашем учебном файле четыре одинаковые части, поэтому их хеши совпадают. После изменения байта проверка обнаруживает повреждение второй части — в выводе это индекс `1`. Повторите проверку повреждённого файла отдельно: ~~~powershell docker compose run --rm -T tools python3 bittorrent/metadata.py verify /work/metadata/lesson.torrent /work/metadata/damaged.bin ~~~ Ожидаем `FAILED bad pieces: [1]` и код завершения 1. Проверка подтверждает соответствие данных выбранным метаданным; доверие к самим метаданным остаётся отдельным вопросом. ## 2. Отключить трекер во время передачи **Предскажите:** смогут ли продолжать загрузку клиент с уже найденным пиром и новый клиент, который ещё никого не знает? В этом опыте другие способы поиска участников отключены: распределённый поиск (DHT), обмен контактами между пирами (PEX) и обнаружение в локальной сети. Новый клиент начинает без сохранённых контактов и может получить их только от трекера. ~~~powershell docker compose run --rm -T tools python3 bittorrent/live.py ~~~ Скрипт запускает трекер и три клиента на основе библиотеки libtorrent. Они передают файл размером 4 MiB: 1. Сид регистрируется на трекере. Клиент `known` получает его контакт и начинает загрузку. 2. Трекер начинает отвечать HTTP 503 — «сервис недоступен». В этот момент запускается новый клиент `fresh`. 3. `known` продолжает получать данные и завершает загрузку. У `fresh` нет пиров и данных. 4. Трекер восстанавливается. После нового запроса `fresh` находит участников и тоже получает файл. Сопоставьте строки `TRACKER`, `known`, `fresh` и `PASS` с этими этапами. Счётчик `bytes_done` показывает, сколько байтов содержимого уже есть у клиента; завершённые файлы дополнительно сверяются с исходным. Трекер нужен для получения контактов. Продолжать обмен по уже установленному соединению можно и при его отказе. Результат для нового клиента зависит от условий: в обычной раздаче ему могут помочь другие способы обнаружения участников. ## Поиск без трекера **Распределённая хеш-таблица (DHT)** позволяет искать контакты участников по infohash без обращения к трекеру. Для входа в DHT клиенту всё равно нужен контакт хотя бы одного её узла. В BitTorrent Mainline DHT используется Kademlia. В [следующем разделе](../chord/readme.md) разберём Chord — другой алгоритм распределённого поиска из лекции. Исходники: [чтение метаданных и проверка частей](metainfo.py), [опыты с метаданными](metadata.py), [локальная передача](live.py). Спецификации: [BEP 3](https://www.bittorrent.org/beps/bep_0003.html), [BEP 5](https://www.bittorrent.org/beps/bep_0005.html).