An example of a p2p file transfer implemented in python

  • 2020-04-02 13:40:42
  • OfStack

Considering the server I have gradually increased, sometimes need to large-scale deployment of the same file, for example because of ease of use systemtap this tool positioning problem, need to handle hundreds of servers at the same time, the kernel is installed - debuginfo this package, the original way of using a source server, using rsync or SCP file transfer can only do a point to distribute this document, issued at this time would be slow, the speed of the based on the above reasons, I wrote a small tool, based on the bt agreement transfer files actual test, Transmission to 10 rooms, more than 70 machine transmission of a 240 m this kernel files, to all the machines, the source using speed 2 m/s upload speed, the test results about as long as the 140 s, all can transfer out, the efficiency is very high, if not under the condition of speed will be faster, to open out the application below.


#!/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 %.2fnstart to seedingn' % 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>

Preparation environment:
You need to install a libtorrent library on all OS.

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

Remember to compile with./configure with enable-python-binding, then mak, make install, go to the binding directory, make, make install
You can run this little tool
Of course, large-scale deployment is impossible to compile and install every single one, as long as the compiled libtorrent. So libtorrent-rasterbar.so

lib=`dirname $0`
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$lib
python bt.py -d -f < Seed file > -s < File save path > -t < Do the kind of time > -u < Limit upload speed >

Usage:
The seed file is first generated on the source server

python bt.py -m -p < The file or folder to publish > -s < Seed storage address >

Release documents
On top of the source server, execute
python bt.py -d -f < Seed file > -s < File save path > -t < Do the kind of time > -u < Limit upload speed >

The default setting of seed time is 100s, and the upload speed is unlimited by default. The unit of speed is KB

The machine down here, you can directly

python bt.py -d -f < Seed file > -s < File save path > -t < Do the kind of time >

As long as there is a machine finished, automatically as a seed, in the process of download and upload, any one machine can be used as the source server, of course there is also the center of the tracker server, the script, I built a tracker source server, into 10.0.1.5 port is 8760 above, of course you also can use opentracker this software build a tracker files, modify the source code of the corresponding parts, and considering the issue is the private files, code as has banned DHT, If you still want to be more secure, you can build a private tracker server by yourself. The specific construction method is to use a search engine to find the construction method!

At present, the basic can be used, the following consideration is a little simpler, using magnetic link, so you can do not have to copy a seed file, using a separate command line can be published the entire file


Related articles: