6 July 2013

QLiveBittorrent — консольный bittorrent клиент для просмотра файлов до скачивания

Qt
Ровно месяц назад была опубликована статья LiveDC — Быстрый доступ к p2p файлам. Смысл ее в том, что Erty_Hackward написал DC-клиент с возможностью просмотра файлов до их окончательной загрузки. С его помощью можно, например, смотреть фильмы спустя пару минут после начала закачки, перематывать их, смотреть с любого момента. А можно извлечь нужный файл из большого архива, не перекачивая целый архив.

Мне очень понравилась идея этой программы. Но она написана на C#. А хотелось бы использовать ее в линуксе. Поэтому с разрешения автора я с большим удовольствием взялся за создание аналогичной программы для линукса. В результате получился консольный битторрент клиент QLiveBittorrent.




Как оно работает

Расскажу о работе QLiveBittorrent на примере скачивания фильма. Ну, например, мой друг выложил в сеть видеозапись выпускного вечера, недавно прошедшего в нашей школе, а я хочу ее скачать, и еще раз насладиться этим незабываемым зрелищем.

Я начинаю скачивать фильм. Указываю папку, куда его надо подмонтировать. И тут же пытаюсь его открыть. Фильм открывается 1-2 мин — в зависимости от скорости. Начинаю смотреть — лагов, как правило, нет, если скорости хватает. Далее я перематываю фильм на середину. Наблюдаю тормоза ~30 сек, и продолжаю смотреть его с середины.

Происходит примерно следующее. Изначально, в момент открытия фильма в плеере, программа скачивает первые несколько блоков фильма и последний блок, чтоб получить информацию о его продолжительности. Далее она продолжает скачивать фильм с начала. Но в момент перемотки фильма на середину, программа начинает скачивать именно тот блок, который был запрошен плеером.

Кроме скачивания фильмов, программу можно использовать для работы с архивами, iso-образами, для просмотра папок с огромным числом картинок. Это очень удобно — начать качать архив, и с самого начала, не дожидаясь пока он скачается, открыть его, сразу указать, какой файл тебе нужен, и скачать именно его.

Как оно начиналось

После того, как я осознал, что будет проще написать свое, чем пытаться портировать LiveDC на линукс, я сразу же приступил к разработке.

Сначала я думал встроить свой функционал в мой любимый bittorrent клиент. Но после просмотра исходников это желание отпало. Миллионы файлов, везде defin-ы на разные системы, все это в виде простыни, и ничего не понятно. Однако, под впечатлением от qbittorrent, я выбрал тот же инструментарий.
  1. Qt5
  2. libtorrent-rasterbar
  3. FUSE

За день был написан драйвер файловой системы qlive.
Еще за день — графика и скачивание торрентов.
Выглядело это примерно так:


На этом разработка впала в ступор. Программа работала, докачивала необходимые куски, но регулярно получала SIGSEGV (ошибка «программа обратилась не по адресу»). В это же время я грустно смотрел на функционал qbittorrent и utorrent, и до меня медленно доходило, что энтузиазма на месяцы разработки у меня не хватит…

Второе дыхание

Второе дыхание открылось, когда я решил забить на GUI. Кому он нужен? На его поддержку уходит слишком много нервов! Так появился консольный битторрент клиент. А затем появилась интересная идея разделить сидирующие торренты от качающихся.

В результате программа оказалась разделенной на качающую часть, которая умеет монтировать недокачанные файлы, ограничивать скорость скачивания и быть обычным торрент-клиентом и сидирующую часть (seed-manager), которая умеет раздавать то, что скачано, а также ограничивать скорость отдачи.


Интересные моменты разработки

  1. Иногда, тестируя закачку торрентов, я с удивлением обнаруживал, что скорость скачивания превосходит максимальную скорость моего роутера — 802.11G ~2MБ/с. Она достигала 40-50 МБ/с, что было в принципе невозможно! Я пытался валить все на кеши. Однако, выяснилось, что у меня было запущено 2 клиента на компьютере, которые и обменивались между собой информацией на скорости чтения жесткого диска. Один читает, другой пишет. Впоследствии я использовал это для тестирования.

  2. Из-за того, что клиент консольный, мне пришлось разбираться с сигналами завершения. Я добавил обработку сигнала SIGTERM (сигнал для запроса завершения процесса). Во время дебага, когда я посылал SIGTERM «руками», он успешно перехватывался и обрабатывался. Однако, на практике, когда я в терминале жал ctrl-c, сигнал не обрабатывался. Оказалось, что терминал посылает не SIGTERM, а SIGINT (сигнал для остановки процесса пользователем с терминала). Это меня поразило. Оказывается, при нажатии ctrl-c идет сигнал не «останови процесс», а «пользователь хочет, чтоб процесс остановился». Наверное, можно придумать глубокий смысл разницы этих процессов, но это было довольно неожиданно и странно.

  3. Несмотря на то, что клиент консольный, мне хотелось, чтобы какое-то подобие GUI все же оставалось. Но ведь, если приложение консольное, то хочется, чтобы оно запускалось в голой консоли (TTY), а это невозможно при наличии GUI… Или возможно? Для этого надо понимать, как работает графика в линуксе.

    А работает она примерно так: есть X-server, есть клиенты. В какой-то момент клиент подключается. Вопрос — когда это происходит? Экспериментальным путем (методом пристального взгляда) я выяснил, что подключение происходит в момент создания QApplication. Соответственно, если нужна графика, то я создаю QApplication, если нет — QCoreApplication. Таким образом, программа может запускаться как в голой консоли, так и с графическим мини-интерефейсом.

  4. Смешивание Qt и libtorrent — это чистый ад. Мои нервы в конце концов не выдержали, и я начал пытаться переводить все в Qt. К сожалению, libtorrent использует std, поэтому весь мой код увешан QString::fromStdString(string) и QString.toStdString(), а так же конверсиями vector char, QVector char, QByteArray и т.п.

  5. Во время разработки я столкнулся с неприятной проблемой. В один прекрасный момент к программе подключаются медленные пиры и начинают неторопливо отдавать нужные куски. При этом в среднем скорость закачки хорошая, но задержки из-за них недопустимые. Я пытался с этим бороться. В какой-то степени задачу удалось решить за счет того, что первые 2 минуты программа ищет быстрых пиров, а затем ограничивает их максимальное число пятью пирами. Это позволяет отшивать большинство медленных пиров.

  6. Для того, чтобы после полуночи не было проблем с вычитанием времени, в программе реализована функция midnight(), которая каждую секунду проверяет, не полночь ли сейчас? В течение 5 секунд после полуночи программу колбасит — она при обновлении информации на экране обнуляет все временные счетчики, игнорируя запросы пользователя. Такой вот редкостный костыль. Я его за 3 минуты до полуночи написал.

Список фич

  1. Если торрент опубликовали только что, то отношение количества сидеров к личерам слишком маленькое. Это влечет за собой почти полную невозможность скачать такой торрент за разумное время. Поэтому в QLiveBittorrent добавлена возможность «превращения» в обычного торрент-клиента. Для этого надо нажать клавишу 'a' (английскую).

  2. При чтении подмонтированных файлов программы впадают в ступор, пока необходимые куски не будут скачаны. Но они обязательно из него выходят, когда это происходит. Это особенность программы.

  3. Авторитетные источники утверждают, что на канале 600КБ/с фильм весом 1.45G с внешней звуковой дорожкой и субтитрами проигрывается без лагов.

  4. Если нажать на клавиатуре ctrl-c (или послать SIGTERM), то программа начнет завершаться — сбрасывать данные на жесткий диск и отправлять информацию трекерам. После сброса данных можно нажать ctrl-c — тогда информация не будет послана трекерам. Это сделано, потому что меня очень расстраивают программы, которые невозможно завершить.

Источники

  1. Erty_Hackward — оригинальная идея
  2. ximaera — рассказал про то, как надо парсить параметры из командной строки.
  3. статья про boost::program_options
  4. Libtorrent api — хорошая библиотека, но эмоции от одностраничной документации непередаваемы.
  5. github.com/qbittorrent/qBittorrent — читал исходники, но ничего не понял.

Скачивание

Исходники
ArchLinux (AUR)
linux-x86-64

Для работы требуются библиотеки boost, Qt, libtorrent-rasterbar.
Настройки хранятся по адресу ~/.qlivebittorrent

UPD 00:30
Забыл описать еще две фичи:
  1. После загрузки торрента, он автоматически добавляется в список сидирования. Если seed-manager уже запущен, то он добавится в список в течение 10 минут.
  2. Если торрент был удален, то он будет удален из списка сидирования при первом же запросе.


UPD 18:00
DAP-DarkneSS выложил версию под OpenSUSE. Спасибо.
Версия под OpenSUSE

UPD 23:15
В выложенной версии не работало GUI. В чем ошибка я так и не понял, но требуемый костыль найден.
Файлы перезалиты.

UPD +месяц
DAP-DarkneSS выложил версии под Debian, Ubuntu и Fedora. Спасибо.
Debian и Ubuntu
Fedora
Tags:bittorrentp2plinuxqtконсоль
Hubs: Qt
+136
32.8k 249
Comments 91
Popular right now
Administrator Linux. Professional
January 18, 202180,000 ₽OTUS
Безопасность Linux
February 12, 202130,000 ₽OTUS
SEO-специалист
December 7, 202064,900 ₽Нетология
UX-дизайнер
December 7, 202047,940 ₽Нетология
Top of the last 24 hours