Пример TCP-соединения по протоколу Bittorrent

Я пытаюсь реализовать клиент BitTorent, и я застрял на той части, где я успешно подключился к узлу, но я не знаю, как общаться с узлом.

Мне удалось расшифровать файл метаданных торрента, я успешно получил оттуда всю информацию, я подключился к пиру по TCP, я отправляю сообщение рукопожатия, я получаю сообщение рукопожатия обратно от пира, но после этого я не получаю любое сообщение от однорангового узла (я ожидал получить сообщения). Я попытался отправить одноранговому узлу сообщение о разблокировке и начал получать некоторые данные, но я не знаю, как понимать эти данные.

Это то, что у меня есть до сих пор:

s.connect((ip, port))
print "Connected"

message = "%s%s%s%s%s" % (chr(19), "BitTorrent protocol", 8 * chr(0),
                         handshake_params["info_hash"], 
                         handshake_params["peer_id"]

s.send(message)
handshake_data = s.recv(4096)

# unchoke
m = struct.pack(">IB", 1, 1)
s.send(m)
data = s.recv(4096)

print handshake_data
print struct.unpack("B" * len(data), data)

И это вывод:

BitTorrent protocolp    p�I0a��9"x`��-UT3450-��kP+�BG   ���������
(255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 231, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 255, 251, 255, 255, 255, 255, 255, 255, 223, 255, 255, 255, 239, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 255, 255, 255, 255, 255, 127, 255, 221, 255, 255, 255, 255, 255, 191, 191, 255, 255, 127, 255, 255, 255, 255, 191, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 255, 255, 255, 255, 255, 255, 247, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 255, 255, 255, 255, 255, 255, 255, 255, 251, 255, 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 0, 0, 0, 5, 4, 0, 0, 4, 191, 0, 0, 0, 5, 4, 0, 0, 1, 123, 0, 0, 0, 5, 4, 0, 0, 2, 122, 0, 0, 0, 5, 4, 0, 0, 2, 126, 0, 0, 0, 5, 4, 0, 0, 2, 177, 0, 0, 0, 5, 4, 0, 0, 2, 104, 0, 0, 0, 5, 4, 0, 0, 1, 37, 0, 0, 0, 5, 4, 0, 0, 0, 174, 0, 0, 0, 5, 4, 0, 0, 4, 157, 0, 0, 0, 5, 4, 0, 0, 0, 4, 0, 0, 0, 5, 4, 0, 0, 3, 172, 0, 0, 0, 5, 4, 0, 0, 2, 241, 0, 0, 0, 5, 4, 0, 0, 1, 90, 0, 0, 0, 5, 4, 0, 0, 3, 251, 0, 0, 0, 5, 4, 0, 0, 2, 200, 0, 0, 0, 5, 4, 0, 0, 0, 179, 0, 0, 0, 5, 4, 0, 0, 0, 180, 0, 0, 0, 5, 4, 0, 0, 3, 113, 0, 0, 0, 5, 4, 0, 0, 4, 181, 0, 0, 0, 5, 4, 0, 0, 1, 16, 0, 0, 0, 5, 4, 0, 0, 2, 169, 0, 0, 0, 5, 4, 0, 0, 4, 81, 0, 0, 0, 5, 4, 0, 0, 2, 57, 0, 0, 0, 5, 4, 0, 0, 1, 219)

Данные рукопожатия выглядят нормально. Чего я не могу понять, так это почему у меня там так много 255 байт. Я пытался декодировать сообщение, используя формат length_prefix, message_id, payload, но поскольку я получаю так много 255 байтов в начале, это приводит к тому, что сообщение имеет огромную длину, и у меня нет такого большого сообщения.

Есть ли какой-либо шум, который я должен попытаться отфильтровать? Если вы сильно прокрутите вправо, вы увидите, что в какой-то момент байты начинают прилично, но я не знаю, что делать с началом сообщения.


person Tiberiu Savin    schedule 01.11.2015    source источник


Ответы (1)


с.recv(4096)

Вы просто читаете блок данных неопределенной длины, предположительно из буфера TCP.

Bittorrent основан на сообщениях. TCP — это поток байтов, что означает, что он не разделяет данные, отправленные удаленным узлом, на сообщения, вам придется делать это самостоятельно.

person the8472    schedule 01.11.2015
comment
Я знаю это, но я не знаю, как нарезать данный поток в битторрент-сообщениях. Протокол bittorrent говорит, что формат сообщения — это length_prefix (4 байта с обратным порядком байтов), message_id (1 байт) и полезная нагрузка (length_prefix — 1 байт). Однако первые 4 байта в потоке равны 255, что дает огромную длину, а у меня даже не так много байтов. - person Tiberiu Savin; 01.11.2015
comment
Я вижу 2 recv там. Это уже разрывает ваш поток на два куска, которые не разделены какой-либо значимой границей. надо смотреть весь поток. Опять же, выполнение произвольного (до 4096 байт) чтения не даст вам ничего при полезных смещениях. Вы не рассуждаете об этом как о непрерывном потоке. - person the8472; 01.11.2015
comment
Да, и я проверил это на самом деле. Первое сообщение, которое я получаю от recv, — это сообщение о рукопожатии, и я проверил, что там ничего не осталось. Все биты в первом сообщении recv учитываются и являются частью сообщения квитирования. По сути, даже если бы я объединил два сообщения и попытался разделить, я бы получил то же самое, потому что я бы успешно проанализировал сообщение рукопожатия в начале, а затем у меня было бы 4 255 байтов, которые должны представлять длину следующего сообщения, но это неверно потому что это было бы слишком большим. - person Tiberiu Savin; 01.11.2015
comment
Я также только что заменил второй recv на некоторое время, в течение которого я продолжаю вызывать s.recv, пока не получу тайм-аут из сокета (чтобы убедиться, что я получаю все из буфера сокета), но у меня все еще есть та же проблема. - person Tiberiu Savin; 01.11.2015
comment
Да это смущает. По-видимому, я неправильно расшифровал сообщение рукопожатия и думал, что все учтено, но на самом деле в конце осталось несколько байтов, которые я пропустил, и это были именно те, которые мне были нужны, которые идентифицировали сообщение битового поля. Да, теперь я знаю, что мне делать, спасибо за все и извините. Это была глупая ошибка. - person Tiberiu Savin; 01.11.2015
comment
Так что да, если все смотрят на этот вопрос в поисках ответов, сообщение рукопожатия содержит дополнительные байты из сообщения рукопожатия. Я изменил свой код вместо recv(4096) я делаю некоторое время True: recv(4096) до истечения времени ожидания сокета (вам также нужно добавить socket.settimeout() иначе сокет блокируется по умолчанию) и сообщение рукопожатия будет содержат сообщение битового поля в конце конкатенации. - person Tiberiu Savin; 01.11.2015