Проектная лаборатория
Собственный BitTorrent
Этап 10 · Основные этапы
Скачивание фрагмента
Русский перевод заданий CodeCrafters. Примеры подготовлены для Go. Выбор языка меняет команды и результаты, но не текст задания.
На этом этапе вы скачаете один фрагмент и сохраните его на диск. На следующем этапе мы объединим фрагменты в файл.
Для скачивания фрагмента программа должна отправлять пиру сообщения протокола пиров. Общая последовательность действий:
- Прочитать торрент-файл и получить URL трекера.
- Вы уже делали это на предыдущих этапах.
- Выполнить GET-запрос трекеру и получить список пиров.
- Вы уже делали это на предыдущих этапах.
- Установить TCP-соединение с пиром и выполнить рукопожатие.
- Вы уже делали это на предыдущих этапах.
- Обменяться несколькими сообщениями протокола пиров, чтобы скачать файл.
- Именно эту часть вы реализуете на этом этапе.
Сообщения пиров
Сообщение пира состоит из префикса длины сообщения (4 байта), идентификатора сообщения (1 байт) и полезной нагрузки переменного размера.
После завершения рукопожатия нужно обменяться следующими сообщениями:
- Дождаться сообщения
bitfieldот пира, указывающего, какие фрагменты у него есть.- Идентификатор этого типа сообщений —
5. - Пока полезную нагрузку можно прочитать и проигнорировать: трекер этого задания гарантирует наличие всех фрагментов у каждого пира.
- Идентификатор этого типа сообщений —
- Отправить сообщение
interested.- Идентификатор
interested—2. - Полезная нагрузка пуста.
- Идентификатор
- Дождаться ответного сообщения
unchoke.- Идентификатор
unchoke—1. - Полезная нагрузка пуста.
- Идентификатор
- Разбить фрагмент на блоки по 16 КиБ (16 * 1024 байт) и отправить сообщение
requestдля каждого блока.- Идентификатор
request—6. - Полезная нагрузка состоит из:
index: индекс фрагмента, начиная с нуля.begin: смещение в байтах внутри фрагмента, начиная с нуля.- Для первого блока это
0, для второго —2^14, для третьего — 2*2^14 и т. д.
- Для первого блока это
length: длина блока в байтах.- Для всех блоков, кроме последнего, это
2^14(16 * 1024). - Последний блок содержит
2^14байт или меньше; вычислите это значение по длине фрагмента.
- Для всех блоков, кроме последнего, это
- Идентификатор
- Дождаться сообщения
pieceдля каждого запрошенного блока.- Идентификатор
piece—7. - Полезная нагрузка состоит из:
index: индекс фрагмента, начиная с нуля.begin: смещение в байтах внутри фрагмента, начиная с нуля.block: данные фрагмента, обычно длиной2^14байт.
- Идентификатор
Получив блоки и объединив их во фрагменты, проверьте целостность каждого фрагмента, сравнив его хеш со значением в торрент-файле.
Тестирующая система запустит вашу программу следующим образом:
$ ./your_program.sh download_piece -o /tmp/test-piece sample.torrent <piece_index>Она проверит, что фрагмент скачан правильно.
Примечания
- При чтении TCP можно получить только часть данных блока, поэтому накапливайте данные, пока не получите блок целиком.
- Необязательно: для ускорения можно отправлять запросы конвейером. В статье об экономике BitTorrent рекомендуется держать одновременно 5 незавершённых запросов, чтобы избежать задержек между отправками блоков.
Проверка в вашей IDE
Нужны Node.js, Git, Go 1.24+ для тестеров и инструменты выбранного языка. Тестеры загружаются и запускаются локально; отдельным проектам нужны дополнительные системные зависимости.
Настройка проекта и IDE
1. Создайте проект один раз
node '/opt/graphlms/tools/project-lab/cli.mjs' init bittorrent ./my-bittorrent --language go2. Откройте папку в IDE
cd ./my-bittorrentРеализуйте требования этапа в созданном проекте.
Запустите из папки проекта
node '/opt/graphlms/tools/project-lab/cli.mjs' submit --stage nd2Запускайте submit из папки проекта. Это локальные проверки, а не сертификаты или результаты аккаунта CodeCrafters.
Результат проверки
go / ЛОКАЛЬНОПодключение к локальной проверке…
Здесь появится результат
Запустите submit в терминале. Страница обновляет результаты каждые 8 секунд.