python实现的一个p2p文件传输实例
考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者scp之类的文件传输方式只能做到一个点往下分发这个文件,这个时候下发的速度就会比较的慢,基于以上原因,我写了一个基于bt协议传输文件的小工具,实际测试,传输到10个机房,70多台机器传输一个240M的这个内核文件,到所有的机器,源采用限速2m/s的上传速度,测试的结果大概只要140s,就可以全部传输完毕,这个效率是非常之高,如果不限速的情况下速度会更快,下面把这个程序开源出来。
#!/usr/bin/envpython
importlibtorrentaslt
importsys
importos
importtime
fromoptparseimportOptionParser
importsocket
importstruct
importfcntl
defget_interface_ip(ifname):
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
returnsocket.inet_ntoa(fcntl.ioctl(s.fileno(),0x8915,struct.pack('256s',
ifname[:15]))[20:24])
defip2long(ip):
returnreduce(lambdaa,b:(a<<8)+b,[int(i)foriinip.split('.')])
defget_wan_ip_address():
interfaces=set(['eth0','eth1','eth2','eth3','em1','em2','em3','em4'])
ip=''
foriininterfaces:
try:
ip=get_interface_ip(i)
if(ip2long(ip)<ip2long('10.0.0.0')orip2long(ip)>ip2long('10.255.255.255'))\
and(ip2long(ip)<ip2long('172.16.0.0')orip2long(ip)>ip2long('172.33.255.255'))\
and(ip2long(ip)<ip2long('192.168.0.0')orip2long(ip)>ip2long('192.168.255.255')):
returnip
except:
pass
returnip
defmake_torrent(path,save):
fs=lt.file_storage()
lt.add_files(fs,path)
iffs.num_files()==0:
print'nofilesadded'
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],lambdax: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"thebttorrentfileisstoreat%s"%save
defdl_status(handle):
whilenot(handle.is_seed()):
s=handle.status()
state_str=['queued','checking','downloadingmetadata',\
'downloading','finished','seeding','allocating','checkingfastresume']
print'\ractive_time:%d,%.2f%%complete(down:%.1fkb/sup:%.1fkB/speers:%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)
defseed_status(handle,seedtime=100):
seedtime=int(seedtime)
ifseedtime<100:
seedtime=100
whileseedtime>0:
seedtime-=1
s=handle.status()
state_str=['queued','checking','downloadingmetadata',\
'downloading','finished','seeding','allocating','checkingfastresume']
print'\rseed_time:%d,%.2f%%complete(down:%.1fkb/sup:%.1fkB/speers:%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)
defremove_torrents(torrent,session):
session.remove_torrent(torrent)
defread_alerts(session):
alert=session.pop_alert()
whilealert:
#printalert,alert.message()
alert=session.pop_alert()
defdownload(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="Thunderdeploysystem"
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()
#printipaddr
ifipaddr=="":
session.listen_on(6881,6881)
else:
session.listen_on(6881,6881,ipaddr)
limit=int(upload_rate_limit)
iflimit>=100:
session.set_upload_rate_limit(limit*1024)
session.set_local_upload_rate_limit(limit*1024)
printsession.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'\nallfiledownloadin%.2f\nstarttoseeding\n'%et
sys.stdout.write('\n')
handle.super_seeding()
seed_status(handle,seedtime)
remove_torrents(handle,session)
assertlen(session.get_torrents())==0
finally:
print'downloadfinished'
if__name__=='__main__':
usage="usage:%prog[options]\n\
%prog-d-f<torrentfile="">-s<filesave=""path="">\n\
or\n\
%prog-m-p<fileor=""dir="">-s<torrentsave=""path="">\n"
parser=OptionParser(usage=usage)
parser.add_option("-d","--download",dest="download",
help="starttodownloadfile",action="store_false",default=True)
parser.add_option("-f","--file",dest="file",
help="torrentfile")
parser.add_option("-u","--upload",dest="upload",
help="setuploadratelimit,defaultisnotlimit",default=0)
parser.add_option("-t","--time",dest="time",
help="setseedtime,defaultis100s",default=100)
parser.add_option("-p","--path",dest="path",
help="tomaketorrentwiththispath")
parser.add_option("-m","--make",dest="make",
help="maketorrent",action="store_false",default=True)
parser.add_option("-s","--save",dest="save",
help="filesavepath,defaultisstoreto./",default="./")
(options,args)=parser.parse_args()
#download(sys.argv[1])
iflen(sys.argv)!=6andlen(sys.argv)!=4andlen(sys.argv)!=8andlen(sys.argv)!=10:
parser.print_help()
sys.exit()
ifoptions.download==Falseandoptions.file!="":
download(options.file,options.save,options.upload,options.time)
elifoptions.make==Falseandoptions.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,makeinstall,进入binding目录,make,makeinstall就
可以运行这个小的工具
当然大规模部署不可能采用每一台都去编译安装的方式,只要把编译出来的libtorrent.solibtorrent-rasterbar.so.7的文件跟bt.py这个文件放到同一个目录,另外写一个shell脚本
lib=`dirname$0` exportLD_LIBRARY_PATH=$LD_LIBRARY_PATH:$lib pythonbt.py-d-f<种子文件>-s<文件保存路径>-t<做种时间>-u<限制上传速度>
使用方法:
首先在源服务器上面生成种子文件
pythonbt.py-m-p<要发布的文件或者文件夹>-s<种子保存地址>
发布文件
在源服务器上面,执行
pythonbt.py-d-f<种子文件>-s<文件保存路径>-t<做种时间>-u<限制上传速度>
其中做种时间默认设置的是100s,上传速度默认不限制,限制的速度单位是KB
下面的机器,直接可以
pythonbt.py-d-f<种子文件>-s<文件保存路径>-t<做种时间>
只要有一台机器完成了,就自动作为种子,在下载的过程中也会上传,任何一台机器都可以作为源服务器,当然了这里面还有中心的tracker服务器,脚本当中,我搭建了一个tracker源服务器,放到10.0.1.5端口是8760上面,当然大家也可以采用opentracker这个软件自己搭建一个tracker服务器,修改其中的源代码对应部分,另外考虑到发布都是私有文件,代码当作已经禁止了dht,如果还想更安全,就自己搭建一个私有的trackerserver,具体搭建方法就使用一下搜索引擎,查找一下搭建的方法!
目前基本做到可以使用,后续考虑更简单一点,采用磁力链接的方式,这样就可以做到不用每台都要拷贝一个种子文件,采用一个单独的命令行就可以发布整个文件