python实现的一个p2p文件传输实例

轻明大大_4384

轻明大大_4384

2016-06-06

2561人浏览

原创

考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者scp之类的文件传输方式只能做到一个点往下分发这个文件,这个时候下发的速度就会比较的慢,基于以上原因,我写了一个基于bt协议传输文件的小工具,实际测试,传输到10个机房,70多台机器传输一个240m的这个内核文件,到所有的机器,源采用限速2m/s的上传速度,测试的结果大概只要140s,就可以全部传输完毕,这个效率是非常之高,如果不限速的情况下速度会更快,下面把这个程序开源出来。

代码如下:


#!/usr/bin/env python

import libtorrent as lt
import sys
import os
import time
from optparse import OptionParser
import socket
import struct
import fcntl

def get_interface_ip(ifname):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    return socket.inet_ntoa(fcntl.ioctl(s.fileno(), 0x8915, struct.pack('256s',
                            ifname[:15]))[20:24])
def ip2long(ip):
    return reduce(lambda a,b:(a
 
def get_wan_ip_address():
    interfaces = set(['eth0', 'eth1', 'eth2', 'eth3', 'em1', 'em2', 'em3', 'em4'])
    ip = ''
    for i in interfaces:
        try:
            ip = get_interface_ip(i)
            if (ip2long(ip) ip2long('10.255.255.255')) \
                and (ip2long(ip) ip2long('172.33.255.255')) \
                and (ip2long(ip) ip2long('192.168.255.255')):
                return ip
        except:
            pass

    return ip

def make_torrent(path, save):
    fs = lt.file_storage()
    lt.add_files(fs, path)
    if fs.num_files() == 0:
        print 'no files added'
        sys.exit(1)

    input = os.path.abspath(path)
    basename = os.path.basename(path)
    t = lt.create_torrent(fs, 0, 4 * 1024 * 1024)

    t.add_tracker("http://10.0.1.5:8760/announce")
    t.set_creator('libtorrent %s' % lt.version)

    lt.set_piece_hashes(t, os.path.split(input)[0], lambda x: sys.stderr.write('.'))
    sys.stderr.write('\n')

    save = os.path.dirname(input)
    save = "%s/%s.torrent" % (save, basename)
    f=open(save, "wb")
    f.write(lt.bencode(t.generate()))
    f.close()
    print "the bt torrent file is store at %s" % save

 
def dl_status(handle):
    while not (handle.is_seed()):
        s = handle.status()

        state_str = ['queued', 'checking', 'downloading metadata', \
                'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']
        print '\ractive_time: %d, %.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d, seeds: %d) %s' % \
                (s.active_time, s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \
                s.num_peers, s.num_seeds, state_str[s.state]),
        sys.stdout.flush()

        time.sleep(1)
def seed_status(handle, seedtime=100):
    seedtime = int(seedtime)
    if seedtime         seedtime = 100
    while seedtime > 0:
        seedtime -= 1
        s = handle.status()

        state_str = ['queued', 'checking', 'downloading metadata', \
                'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']
        print '\rseed_time: %d, %.2f%% complete (down: %.1f kb/s up: %.1f kB/s peers: %d, seeds: %d) %s' % \
                (s.active_time, s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000, \
                s.num_peers, s.num_seeds, state_str[s.state]),
        sys.stdout.flush()

        time.sleep(1)

def remove_torrents(torrent, session):
    session.remove_torrent(torrent)

def read_alerts(session):
    alert = session.pop_alert()
    while alert:
        #print alert, alert.message()
        alert = session.pop_alert()

def download(torrent, path, upload_rate_limit=0, seedtime=100):
    try:
        session = lt.session()
        session.set_alert_queue_size_limit(1024 * 1024)

        sts = lt.session_settings()
        sts.ssl_listen = False
        sts.user_agent = "Thunder deploy system"
        sts.tracker_completion_timeout = 5
        sts.tracker_receive_timeout = 5
        sts.stop_tracker_timeout = 5
        sts.active_downloads = -1
        sts.active_seeds = -1
        sts.active_limit = -1
        sts.auto_scrape_min_interval = 5
        sts.udp_tracker_token_expiry = 120
        sts.min_announce_interval = 1
        sts.inactivity_timeout = 60
        sts.connection_speed = 10
        sts.allow_multiple_connections_per_ip = True
        sts.max_out_request_queue = 128
        sts.request_queue_size = 3

        sts.use_read_cache = False
        session.set_settings(sts)

        session.set_alert_mask(lt.alert.category_t.tracker_notification | lt.alert.category_t.status_notification)
        session.set_alert_mask(lt.alert.category_t.status_notification)

        ipaddr = get_wan_ip_address()
        #print ipaddr
        if ipaddr == "":
            session.listen_on(6881, 6881)
        else:
            session.listen_on(6881, 6881, ipaddr)

        limit = int(upload_rate_limit)
        if limit>=100:
            session.set_upload_rate_limit(limit*1024)
            session.set_local_upload_rate_limit(limit*1024)
        print session.upload_rate_limit()
        torrent_info = lt.torrent_info(torrent)
        add_params = {
            'save_path': path,
            'storage_mode': lt.storage_mode_t.storage_mode_sparse,
            'paused': False,
            'auto_managed': True,
            'ti': torrent_info,
        }

        handle = session.add_torrent(add_params)

        read_alerts(session)
        st = time.time()
        dl_status(handle)
        et = time.time() - st
        print '\nall file download in %.2f\nstart to seeding\n' % et
        sys.stdout.write('\n')
        handle.super_seeding()
        seed_status(handle, seedtime)

        remove_torrents(handle, session)
        assert len(session.get_torrents()) == 0

    finally:
        print 'download finished'

if __name__ == '__main__':
    usage = "usage: %prog [options] \n \
      %prog -d -f -s \n \
      or \n \
      %prog -m -p -s \n"

    parser = OptionParser(usage=usage)
    parser.add_option("-d", "--download", dest="download",
            help="start to download file", action="store_false", default=True)
    parser.add_option("-f", "--file", dest="file",
            help="torrent file")
    parser.add_option("-u", "--upload", dest="upload",
            help="set upload rate limit, default is not limit", default=0)
    parser.add_option("-t", "--time", dest="time",
            help="set seed time, default is 100s", default=100)
    parser.add_option("-p", "--path", dest="path",
            help="to make torrent with this path")
    parser.add_option("-m", "--make", dest="make",
            help="make torrent", action="store_false", default=True)
    parser.add_option("-s", "--save", dest="save",
            help="file save path, default is store to ./", default="./")
    (options, args) = parser.parse_args()
    #download(sys.argv[1])
    if len(sys.argv) != 6 and len(sys.argv) != 4 and len(sys.argv) != 8 and len(sys.argv) != 10:
        parser.print_help()
        sys.exit()
    if options.download == False and options.file !="":
        download(options.file, options.save, options.upload, options.time)
    elif options.make == False and options.path != "":
        make_torrent(options.path, options.save)

准备环境:
需要在所有的os上面安装一个libtorrent的库,下载地址:

http://code.google.com/p/libtorrent/downloads/list

记得编译的时候带上./configure –enable-python-binding,然后mak,make install,进入binding目录,make,make install就
可以运行这个小的工具
当然大规模部署不可能采用每一台都去编译安装的方式,只要把编译出来的libtorrent.so libtorrent-rasterbar.so.7的文件跟bt.py这个文件放到同一个目录,另外写一个shell脚本

代码如下:

lib=`dirname $0`
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$lib
python bt.py -d -f -s -t -u

使用方法:
首先在源服务器上面生成种子文件

代码如下:

python bt.py -m -p -s


发布文件
在源服务器上面,执行

Python Use Agent
Python Use Agent

智能执行Python任务,自动生成、执行代码并反馈结果,无需额外配置,兼容旧命令。

下载

代码如下:

python bt.py -d -f -s -t -u


其中做种时间默认设置的是100s,上传速度默认不限制,限制的速度单位是KB

下面的机器,直接可以

代码如下:

python bt.py -d -f -s -t

只要有一台机器完成了,就自动作为种子,在下载的过程中也会上传,任何一台机器都可以作为源服务器,当然了这里面还有中心的tracker服务器,脚本当中,我搭建了一个tracker源服务器,放到10.0.1.5端口是8760上面,当然大家也可以采用opentracker这个软件自己搭建一个tracker服务器,修改其中的源代码对应部分,另外考虑到发布都是私有文件,代码当作已经禁止了dht,如果还想更安全,就自己搭建一个私有的tracker server,具体搭建方法就使用一下搜索引擎,查找一下搭建的方法!

目前基本做到可以使用,后续考虑更简单一点,采用磁力链接的方式,这样就可以做到不用每台都要拷贝一个种子文件,采用一个单独的命令行就可以发布整个文件

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关文章

python速学教程(入门到精通)
python速学教程(入门到精通)

python怎么学习?python怎么入门?python在哪学?python怎么学才快?不用担心,这里为大家提供了python速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

python

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

60

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

40

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

40

12

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

2026.09.30

40

26

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

2026.09.29

40

15

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

2026.09.23

240

15

Buffalo框架路由与请求处理实操指南
Buffalo框架路由与请求处理实操指南

本专题讲解Buffalo框架路由与请求处理机制,涵盖路由注册与分组、资源路由、Handler编写规范、Context上下文方法、参数绑定、中间件编写挂载、Session与Cookie读写、Flash消息及错误页面定制方法。

2026.09.23

160

15

Buffalo框架零基础入门教程
Buffalo框架零基础入门教程

本专题整理Buffalo框架入门内容,涵盖Go环境准备、buffalo CLI安装、新项目生成、目录结构说明、dev热加载启动、数据库连接配置与常见报错排查,帮助新手按约定优于配置的思路跑通第一个Buffalo框架应用。

2026.09.23

120

15

Conan创建软件包配方指南
Conan创建软件包配方指南

本专题介绍通过conanfile.py创建软件包的方法,讲解包名、版本、依赖和构建设置等基础信息,以及source、build、package、package_info等常用方法的作用及编写思路。

2026.09.22

80

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程