Я пытаюсь узнать, как работают торренты, и написал скрипт python, чтобы отправить запрос на соединение на URL трекера и получить ответ. Я подготовил сообщение о соединении в соответствии с протоколом и отправил его, используя метод sock.send()
, с IP-адресом и портом (проверьте функцию get_peers_list
, она неполна в своей функциональности, поскольку я застрял в части запроса соединения). Я получаю ошибку тайм-аута и не могу двигаться вперед. Это мой сценарий:
from bcoding import bdecode, bencode
import time, hashlib
from urllib.parse import urlparse
import socket
import random
from struct import pack, unpack
def load_from_path(path):
with open(path, 'rb') as file:
contents = bdecode(file)
#random seed to generate peer_id
seed = str(time.time())
return {
"torrent_file": contents,
"piece_length": contents['info']['piece length'],
"pieces": contents['info']['pieces'],
"info_hash": hashlib.sha1( bencode(contents['info']) ).digest(),
"peer_id": hashlib.sha1(seed.encode('utf-8')).digest(),
"announce": contents['announce']
}
class UdpTrackerConnection():
def __init__(self):
self.conn_id = pack('>Q', 0x41727101980)
self.action = pack('>I', 0)
self.trans_id = pack('>I', random.randint(0, 100000))
def to_bytes(self):
return self.conn_id + self.action + self.trans_id
def from_bytes(self, payload):
self.action, = unpack('>I', payload[:4])
self.trans_id, = unpack('>I', payload[4:8])
self.conn_id, = unpack('>Q', payload[8:])
def _read_from_socket(sock):
data = b''
while True:
try:
buff = sock.recv(4096)
print("got some response", buff)
if len(buff) <= 0:
break
data += buff
except socket.error as e:
print(e)
break
except Exception:
print("Recv failed")
break
return data
def get_peers_list(torrent):
parsed = urlparse(torrent['announce'])
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.settimeout(4)
ip, port = socket.gethostbyname(parsed.hostname), parsed.port
tracker_connection_input = UdpTrackerConnection()
message = tracker_connection_input.to_bytes()
sock.sendto(message, (ip, port))
try:
response = _read_from_socket(sock)
except socket.timeout as e:
print("Timeout : %s" % e)
return
except Exception as e:
print("Unexpected error when sending message : %s" % e.__str__())
return
tracker_connection_output = UdpTrackerConnection()
path_to_torrent = "test.torrent"
torrent = load_from_path(path_to_torrent)
get_peers_list(torrent)
Я получаю этот вывод
got some response b'\x00\x00\x00\x00\x00\x00\xe2\x9b{E\xf0U\xfb\x9b\xf2\xc6'
timed out
Я довольно новичок в сокетах здесь, и любая помощь будет полезна.