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

考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用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<<8)+b,[int(i) for i in ip.split('.')])

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.0.0.0') or ip2long(ip) > ip2long('10.255.255.255')) \
        and (ip2long(ip) < ip2long('172.16.0.0') or ip2long(ip) > ip2long('172.33.255.255')) \
        and (ip2long(ip) < ip2long('192.168.0.0') or 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 < 100:
    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 <torrent file=""> -s <file save="" path="">\n \
   or \n \
   %prog -m -p <file or="" dir=""> -s <torrent save="" path="">\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)
</torrent></file></file></torrent>

准备环境:
需要在所有的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 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,具体搭建方法就使用一下搜索引擎,查找一下搭建的方法!

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

(0)

相关推荐

  • Python实现简单的文件传输与MySQL备份的脚本分享

    用python实现简单Server/Client文件传输: 服务器端: #!/usr/bin/python import SocketServer, time class MyServer(SocketServer.BaseRequestHandler): userInfo = { 'leonis' : 'leonis', 'hudeyong' : 'hudeyong', 'mudan' : 'mudan' } def handle(self): print 'Connected from',

  • Python备份Mysql脚本

    复制代码 代码如下: #!/usr/bin/python import os  import time  import ftplib  import traceback #config vars  systempathchr="/" #路径分割符,*nix用"/" win32用"\\" dbuser="root" #数据库用户名  dbpwd="dbpwd" #数据库密码  dbnamelist=[&quo

  • Python实现基于HTTP文件传输实例

    本文实例讲述了Python实现基于HTTP文件传输的方法.分享给大家供大家参考.具体实现方法如下: 一.问题: 因为需要最近看了一下通过POST请求传输文件的内容 并且自己写了Server和Client实现了一个简单的机遇HTTP的文件传输工具 二.实现代码: Server端: 复制代码 代码如下: #coding=utf-8 from BaseHTTPServer import BaseHTTPRequestHandler import cgi class   PostHandler(Base

  • 使用Python发送邮件附件以定时备份MySQL的教程

    最近迁移了wordpress,系统升级为CentOS 6,很奇怪的一个问题,在原来CentOS 5.8下用的很正常的定时备份数据库并通过邮件发送的脚本不能发送附件,其他都正常,邮件内容也是uuencode生成的文件编码,但是就是不产生附件.而且找不出原因,望有知道的不吝赐教. 为了解决这一问题,我用Python写了一个mail客户端,可以发送附件,是一个命令行程序.废话不多说.贴代码: #!/usr/bin/env python #-*- coding: utf8 -*- ''' #======

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

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

  • Python简单爬虫导出CSV文件的实例讲解

    流程:模拟登录→获取Html页面→正则解析所有符合条件的行→逐一将符合条件的行的所有列存入到CSVData[]临时变量中→写入到CSV文件中 核心代码: ####写入Csv文件中 with open(self.CsvFileName, 'wb') as csvfile: spamwriter = csv.writer(csvfile, dialect='excel') #设置标题 spamwriter.writerow(["游戏账号","用户类型","游戏

  • python方法生成txt标签文件的实例代码

    1.如果想要利用代码(不论是python.c++.亦或是matlab)实现生成标签文件,首先,也是灰常重要的一件事就是你的图片集一定要是有规律的命名.数字字母顺序排开.这一点非常重要,相关重命名方法请自行百度或请教大牛. 2.如图为博主的图片集.(注意命名规律) 博主只分为猫和鸟两类. 3.看代码. 在caffe根目录下创建一个我们的工程目录my-caffe-project 创建并编辑create_db.py文件,使用如下指令: vim create_db.py 然后,代码内容就是我们的重点了.

  • 用python编写第一个IDA插件的实例

    IDA插件是经过编译的.功能更强大的IDC脚本,与仅仅使用脚本相比,插件能够执行更加复杂的任务.与编写IDC脚本相比,python显得更为轻巧和强大,IDAPython作为IDA的一个插件,具有IDA SDK的大部分功能,能够帮助我们编写实现IDC脚本语言所有功能的python脚本. 本文将以一个简单的例子开始展示如何使用python编写并安装一个IDA插件. 1.编写插件文件msg.py from idaapi import * class myIdaPlugin(plugin_t): fla

  • Python使用pandas处理CSV文件的实例讲解

    Python中有许多方便的库可以用来进行数据处理,尤其是Numpy和Pandas,再搭配matplot画图专用模块,功能十分强大. CSV(Comma-Separated Values)格式的文件是指以纯文本形式存储的表格数据,这意味着不能简单的使用Excel表格工具进行处理,而且Excel表格处理的数据量十分有限,而使用Pandas来处理数据量巨大的CSV文件就容易的多了. 我用到的是自己用其他硬件工具抓取得数据,硬件环境是在Linux平台上搭建的,当时数据是在运行脚本后直接输出在termin

  • python:print格式化输出到文件的实例

    遇到一个写文件的小程序,需要把print输出改成输出到文件,遇到这个问题的思路是把需要的字符串拼接到一个字符串中,然后在写到文件中,这样做觉得很麻烦,想到之前的学的exec的使用,但是实验后发现exec没有返回值,无法将输出保存在变量中. 查过资料后,发现可以把print的输出直接写到文件里,不需要中间的保存过程,非常有效方便. 格式:print >> fp,格式串 #fp为文件句柄 data=open("D:\data.txt",'w+') print>>da

  • Python模块_PyLibTiff读取tif文件的实例

    Usage example (libtiff wrapper) from libtiff import TIFF # to open a tiff file for reading: tif = TIFF.open('filename.tif', mode='r') # to read an image in the currect TIFF directory and return it as numpy array: image = tif.read_image() # to read al

  • python 批量解压压缩文件的实例代码

    下面给大家介绍python 批量解压压缩文件的实例代码,代码如下所述: #/usr/bin/python#coding=utf-8import os,sys import zipfile open_path='e:\\data'save_path='e:\\data' os.chdir(open_path) #转到路径 #首先,通过zipfile模块打开指定位置zip文件 #传入文件名列表,及列表文件所在路径,及存储路径def Decompression(files,file_path,save

  • python按修改时间顺序排列文件的实例代码

    python按修改时间顺序排列文件,具体代码如下所示: import os def sort_file_by_time(file_path): files = os.listdir(file_path) if not files: return else: files = sorted(files, key=lambda x: os.path.getmtime(os.path.join(file_path, x)))#格式解释:对files进行排序.x是files的元素,:后面的是排序的依据.

随机推荐