这需要我们理解 BitTorrent 的核心概念,并利用强大的库来处理底层的复杂性。
首先,我们要明确一点:“Torrent 服务端”并不同于传统的 HTTP/FTP 服务器。
传统的服务器是“客户端-服务器”(C/S)模型,所有下载者都直接从服务器获取数据,服务器的带宽是瓶颈。而 BitTorrent 是“对等网络”(P2P)模型,它的“服务端”主要扮演两个角色:
Tracker (追踪器): 一个协调服务器,它不存储文件本身,只负责记录哪些 Peer (对等端) 拥有哪些文件块 (Piece)。当一个新的 Peer 加入时,它向 Tracker 查询其他 Peer 的地址,然后直接与其他 Peer 连接交换数据。
Initial Seeder (初始做种者): 第一个拥有完整文件的 Peer。它启动后,其他 Peer 就可以从它那里下载文件的第一批数据块。一旦其他 Peer 下载了某些数据块,它们也可以把这些数据块上传给别的 Peer。
因此,您需要实现的是 .torrent 文件的创建、一个 Tracker (或者使用公共 Tracker),以及一个持续运行的 Seeder 客户端。
我们将使用业界标准库 libtorrent 的 Python 绑定 python-libtorrent 来完成这个任务,因为它是性能最高、功能最全的选择。
核心步骤概览
环境准备: 安装 python-libtorrent。
第1步:创建 .torrent 元数据文件: 针对您要分发的文件,生成一个 .torrent 文件。这个文件包含了 Tracker 的地址和文件的哈希信息。
第2步:运行 Tracker (可选但推荐): 为了私有分发,您需要运行自己的 Tracker。对于简单演示,我们可以暂时跳过自己编写,而是假设一个 Tracker 正在运行。
第3步:运行 Seeder (您的“文件分发服务”): 这是一个 Python 脚本,它加载 .torrent 文件,并作为第一个种子开始向网络提供文件。
第4步:运行 Downloader (客户端): 其他用户使用这个 .torrent 文件,通过您的 Tracker 找到您的 Seeder 和其他 Peer,进行 P2P 下载。
环境准备
首先,安装 python-libtorrent 库。
pip install python-libtorrent
详细实现步骤
第1步:创建 .torrent 文件这个脚本会读取一个您指定的文件(例如 my_large_file.zip),并为其创建一个 .torrent 文件。
create_torrent.py
import libtorrent as lt
import time
import os
# --- 配置 ---
# 替换为您的 Tracker 的地址。
# 如果您在本地运行 Tracker,通常是 http://127.0.0.1:6969/announce
# 您也可以使用公共的 open trackers,但不推荐用于私有文件。
TRACKER_URL = "http://127.0.0.1:6969/announce"
# 您想要分发的文件或目录的路径
FILE_PATH = "./my_large_file.zip"
# 生成的 .torrent 文件的保存路径
TORRENT_FILE_PATH = "./my_file.torrent"
def create_torrent_file(file_path, tracker_url, output_path):
"""
为指定的文件或目录创建 .torrent 文件。
"""
fs = lt.file_storage()
# 使用 libtorrent 的工具函数来填充文件存储对象
lt.add_files(fs, file_path)
if fs.num_files() == 0:
print(f"错误: 路径 '{file_path}' 中没有找到文件。")
return
# 创建 torrent
# create_torrent 构造函数需要一个 file_storage 对象
t = lt.create_torrent(fs)
t.add_tracker(tracker_url)
t.set_creator("My Python Torrent Creator")
# 将其设置为私有 torrent,这样客户端将只连接到此 Tracker 中的 Peer
# 对于内部文件分发非常有用
t.set_priv(True)
print("正在计算文件哈希...")
# set_piece_hashes 需要一个路径来找到文件并计算哈希
# 第一个参数是文件/目录的根路径
root_path = os.path.dirname(os.path.abspath(file_path)) if os.path.isfile(file_path) else os.path.abspath(file_path)
lt.set_piece_hashes(t, root_path)
# 获取 torrent 的 B编码 形式
torrent_data = t.generate()
# 将 B编码 的数据写入文件
with open(output_path, "wb") as f:
f.write(lt.bencode(torrent_data))
print(f"成功创建 .torrent 文件: {output_path}")
print(f"Info Hash: {t.info_hash()}")
if __name__ == "__main__":
# 在运行前,先创建一个用于测试的大文件
if not os.path.exists(FILE_PATH):
print(f"正在创建测试文件: {FILE_PATH}")
with open(FILE_PATH, "wb") as f:
f.write(os.urandom(20 * 1024 * 1024)) # 创建一个 20MB 的随机文件
create_torrent_file(FILE_PATH, TRACKER_URL, TORRENT_FILE_PATH) 第2步:运行一个简单的 Tracker编写一个功能完善、高性能的 Tracker 是一个复杂的任务。幸运的是,有很多开源的 Tracker 可以直接使用。您不需要用 Python 从头写。
一个简单的方式是使用 opentracker 或者一个用 Python 编写的简单 Tracker 如 pytracker。
为了演示,您可以下载并运行一个简单的 Python Tracker: bep_0015_tracker.py (这是一个符合 UDP Tracker 协议的简单实现)。
但更简单的方式是假设 Tracker 已经在运行。为了让上面的代码能跑通,您需要一个在 http://127.0.0.1:6969/announce 监听的 Tracker。
第3步:Seeder (文件分发服务)这个脚本会加载 .torrent 文件,并开始做种。这就是您的“服务端”的核心。它需要一直运行,以便其他 Peer 可以连接并下载。
seed_file.py
import libtorrent as lt
import time
import os
# --- 配置 ---
TORRENT_FILE_PATH = "./my_file.torrent"
# 文件的存放目录
SAVE_PATH = "."
def run_seeder(torrent_file_path, save_path):
"""
加载 .torrent 文件并作为 Seeder 持续运行。
"""
ses = lt.session({'listen_interfaces': '0.0.0.0:6881'})
params = {
'save_path': save_path,
'storage_mode': lt.storage_mode_t.storage_mode_sparse,
}
with open(torrent_file_path, 'rb') as f:
torrent_info = lt.bdecode(f.read())
params['ti'] = lt.torrent_info(torrent_info)
h = ses.add_torrent(params)
print(f"开始为 '{h.name()}' 做种...")
print(f"Info Hash: {h.info_hash()}")
try:
while True:
s = h.status()
state_str = [
'排队中', '检查文件中', '下载元数据',
'下载中', '完成', '做种中',
'分配空间', '检查恢复数据'
]
print(f'\r状态: {state_str[s.state]} {s.progress * 100:.2f}% '
f'| 下载速度: {s.download_rate / 1000:.1f} kB/s '
f'| 上传速度: {s.upload_rate / 1000:.1f} kB/s '
f'| 连接数: {s.num_peers} ', end='')
time.sleep(1)
except KeyboardInterrupt:
print("\n停止做种...")
ses.pause()
if __name__ == "__main__":
if not os.path.exists(TORRENT_FILE_PATH):
print(f"错误: .torrent 文件 '{TORRENT_FILE_PATH}' 不存在。")
print("请先运行 create_torrent.py 来创建它。")
else:
run_seeder(TORRENT_FILE_PATH, SAVE_PATH) 第4步:Downloader (客户端)这个脚本模拟一个用户(Peer)下载文件。它的代码和 Seeder 非常相似,因为在 BitTorrent 网络中,下载者同时也是上传者。
download_file.py
import libtorrent as lt
import time
import sys
import os
# --- 配置 ---
TORRENT_FILE_PATH = "./my_file.torrent"
# 下载的文件将保存到这个目录
SAVE_PATH = "./downloads"
def run_downloader(torrent_file_path, save_path):
"""
加载 .torrent 文件并下载内容。
"""
if not os.path.exists(save_path):
os.makedirs(save_path)
ses = lt.session({'listen_interfaces': '0.0.0.0:6882'}) # 使用不同端口
params = {
'save_path': save_path,
'storage_mode': lt.storage_mode_t.storage_mode_sparse,
}
with open(torrent_file_path, 'rb') as f:
torrent_info = lt.bdecode(f.read())
params['ti'] = lt.torrent_info(torrent_info)
h = ses.add_torrent(params)
print(f"开始下载 '{h.name()}'...")
print(f"保存到: {os.path.abspath(save_path)}")
try:
while not h.status().is_seeding:
s = h.status()
state_str = [
'排队中', '检查文件中', '下载元数据',
'下载中', '完成', '做种中',
'分配空间', '检查恢复数据'
]
print(f'\r状态: {state_str[s.state]} {s.progress * 100:.2f}% '
f'| 下载速度: {s.download_rate / 1000:.1f} kB/s '
f'| 上传速度: {s.upload_rate / 1000:.1f} kB/s '
f'| 连接数: {s.num_peers} ', end='')
time.sleep(1)
print(f"\n\n下载完成!文件已保存到 '{os.path.abspath(save_path)}' 目录。")
# 下载完成后,让它再做种 60 秒
print("现在开始做种 60 秒...")
time.sleep(60)
except KeyboardInterrupt:
print("\n停止下载...")
ses.pause()
if __name__ == "__main__":
if not os.path.exists(TORRENT_FILE_PATH):
print(f"错误: .torrent 文件 '{TORRENT_FILE_PATH}' 不存在。")
else:
run_downloader(TORRENT_FILE_PATH, SAVE_PATH) 启动 Seeder (您的分发服务):
打开一个新的终端。
运行 seed_file.py,并让它一直保持运行。
python seed_file.py
您会看到它显示状态为“做种中”,等待其他 Peer 连接。
启动 Downloader (客户端):
打开第三个终端。
运行 download_file.py。
python download_file.py
您会看到下载进度开始变化,并且 Seeder 终端中的“上传速度”和“连接数”也会相应地变化。下载完成后,它会自动开始做种。
重要注意事项
防火墙和 NAT: P2P 网络最大的障碍是防火墙和网络地址转换 (NAT)。如果您的 Seeder 和 Downloader 位于严格的 NAT 之后,它们可能无法直接连接。libtorrent 支持 UPnP 和 NAT-PMP 来自动进行端口映射,但这不一定总能成功。在生产环境中,确保 Seeder 服务器具有公网 IP 或正确配置了端口转发是至关重要的。
Trackerless (无追踪器) Torrent: libtorrent 强大之处在于它原生支持 DHT (分布式哈希表)、PEX (Peer Exchange) 和 LSD (Local Service Discovery)。这意味着即使没有 Tracker,只要网络中有一个 Peer,新的 Peer 就可以通过 DHT 网络找到它。要在 create_torrent.py 中启用它,只需在创建 torrent 后不调用 t.add_tracker() 即可(或者同时使用 Tracker 和 DHT)。
扩展性: 这个示例非常基础。对于一个真正的分发系统,您需要将 Seeder 脚本作为一个后台服务 (daemon) 来运行,并可能需要一个 Web 前端来上传文件并自动生成和管理 .torrent 文件。
网友回复


