首页 > 解决方案 > Python 与 UDP BitTorrent 跟踪器建立连接

问题描述

我正在学习如何与udp跟踪器建立连接以发送连接并接收响应。但是,我不确定为什么我没有收到连接响应。

我试图从中获取文件的种子位于此处

# 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解析链接来获取诸如xttrdn等元素。

from urllib import parse
processed_mag_link = parse.parse_qs(parse.urlparse(mag_link).query)

我已经浏览了一些文档bit torrent protocolsudp 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]

标签: pythonudpbittorrentmagnet-uri

解决方案


推荐阅读