我正在学习如何与udp
跟踪器建立连接以发送连接并接收响应。但是,我不确定为什么我没有收到连接响应。
我尝试从中获取文件的torrent位于here
# It produces this magnet link.
mag_link = 'magnet:?xt=urn:btih:5daa22057577521a378b71e0f0de6a934bd5c2ea&tr=http%3A%2F%2Facademictorrents.com%2Fannounce.php&tr=udp%3A%2F%2Ftracker.publicbt.com%3A80%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80%2Fannounce'
之后,我使用urllib.parse
来解析链接,以获取xt
,tr
,dn
等元素。
from urllib import parse
processed_mag_link = parse.parse_qs(parse.urlparse(mag_link).query)
我已经在bit torrent protocols
和udp connections
上查看了一些文档,并获得了以下代码。如果您能与我分享为什么我无法从跟踪器获得连接响应,我将非常感激。
import random
import socket
import struct
from urllib import parse
from urllib.parse import urlparse
def magnet_link_decode(mag_link):
# Parsing of mag_link
processed_mag_link = parse.parse_qs(parse.urlparse(mag_link).query)
# Renaming of mag_link
processed_mag_link = {
'exact_topic': processed_mag_link.get('xt'),
'display_name': processed_mag_link.get('dn'),
'tracker_name': processed_mag_link.get('tr')
}
print(processed_mag_link['tracker_name'])
return processed_mag_link
def announce_udp(processed_nag_link):
trackers = magnet_link_decode(processed_nag_link)['tracker_name']
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(5)
for tracker in trackers:
tracker = urlparse(tracker)
try:
if tracker.scheme == 'udp':
print('connecting to: ', tracker.hostname)
connection = (socket.gethostbyname(tracker.hostname), tracker.port)
request, transaction_id = udp_create_connection_request()
sock.sendto(request, connection)
buffer = sock.recvfrom(1048)[0]
connection_id = udp_parse_connection_response(buffer, transaction_id)
print(connection_id)
elif tracker.scheme == 'http':
pass # do nothing for now
except socket.gaierror:
print('Connection to: {err} failed..'.format(err=tracker.hostname))
except socket.timeout:
pass
def udp_parse_connection_response(buf, sent_transaction_id):
print('connecting')
if len(buf) < 16:
raise RuntimeError("Wrong response length getting connection id: %s" % len(buf))
action = struct.unpack_from("!i", buf)[0] # first 4 bytes is action
res_transaction_id = struct.unpack_from("!i", buf, 4)[0] # next 4 bytes is transaction id
if res_transaction_id != sent_transaction_id:
raise RuntimeError("Transaction ID doesnt match in connection response! Expected %s, got %s"
% (sent_transaction_id, res_transaction_id))
if action == 0x0:
connection_id = struct.unpack_from("!q", buf, 8)[0] # unpack 8 bytes from byte 8, should be the connection_id
return connection_id
elif action == 0x3:
error = struct.unpack_from("!s", buf, 8)
raise RuntimeError("Error while trying to get a connection response: %s" % error)
def udp_create_connection_request():
connection_id = 0x41727101980 # default connection id
action = 0x0 # action (0 = give me a new connection id)
transaction_id = int(random.randrange(0, 255))
print("Transaction ID :", transaction_id)
buffer = struct.pack("!q", connection_id) # first 8 bytes is connection id
buffer += struct.pack("!i", action) # next 4 bytes is action
buffer += struct.pack("!i", transaction_id) # next 4 bytes is transaction id
return buffer, transaction_id
对于第一部分,magnet_link_decode
实质上是解析磁链接以获得info_hash
以及跟踪器。
announce_udp
的下一部分是查看我是否可以连接并从跟踪器返回响应。我不确定这是否正确,但它似乎无法从代码buffer = sock.recvfrom(1048)[0]