Python模拟P2P大文件传输

编程 空心菜 发表了文章 0 个评论 4217 次浏览 2015-12-14 23:44 来自相关话题

一、需求及应用场景 考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器 ...查看全部


一、需求及应用场景


考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用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 [i] 1024 [/i] 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 -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)


三、使用


1、环境准备
需要在所有的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 <限制上传速度>

2、使用方法
在源服务器上生成种子文件:
python bt.py -m -p <要发布的文件或者文件夹> -s <种子保存地址>

在源服务器上发布文件:
python bt.py -d -f <种子文件> -s <文件保存路径> -t <做种时间> -u <限制上传速度>
其中做种时间默认设置是100s,上传速度默认不限制,限制速度的单位是kb。
 
只要有一台机器完成了,就自动作为种子,在下载的过程中也会上传,任何一台机器都可以作为源服务器,当然了这里面还有中心的tracker服务器,脚本当中,我搭建了一个tracker源服务器,放到10.0.1.5端口是8760上面,当然大家也可以采用opentracker这个软件自己搭建一个tracker服务器,修改其中的源代码对应部分,另外考虑到发布都是私有文件,代码当作已经禁止了dht,如果还想更安全,就自己搭建一个私有的tracker server,具体搭建方法就使用一下搜索引擎,查找一下搭建的方法!

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

在使用实用中进行大文件传输时,可以再结合ansible、saltstack等自动化运维工具需要在多台主机之间传大文件时,可以通过该文件加快传输速度,增加网络利用率。

Python input和raw_input的区别

编程 空心菜 发表了文章 1 个评论 4265 次浏览 2015-12-14 23:18 来自相关话题

使用input和raw_input都可以读取控制台的输入,但是input和raw_input在处理数字时是有区别的 纯数字输入 当输入为纯数字时 []input返回的是数值类型,如int,floa ...查看全部
使用input和raw_input都可以读取控制台的输入,但是input和raw_input在处理数字时是有区别的


纯数字输入


当输入为纯数字时
    []input返回的是数值类型,如int,float[/][]raw_inpout返回的是字符串类型,string类型[/]

cb.png


输入字符串为表达式


input会计算在字符串中的数字表达式,而raw_input不会。
如输入 "57 + 3":
input会得到整数60
raw_input会得到字符串"57 + 3"
cb1.png

输入字符串结果如下:
cb3.png

通过上面的实验我们知道input它会根据用户输入变换相应的类型,而且如果要输入字符和字符串的时候必须要用引号包起来,而raw_input则是不管用户输入什么类型的都会转变成字符型.


python input的实现


python input的文档,你可以发现input其实是通过raw_input来实现的,原理很简单,就下面一行代码:
def input(prompt):
return (eval(raw_input(prompt)))

TVR时光机

科技前沿 Rock 发表了文章 1 个评论 3674 次浏览 2015-12-14 22:49 来自相关话题

TVR将技术与艺术完美融合,打造国内最好的VR游戏。   TVR时光机虚拟现实是北大几位优秀研究生及专业游戏行业人士共同创立,主要在做的是基于头戴式显示设备的虚拟现实内容制作,目标是打造最优秀的虚拟现实内容。主营业务《Finding ...查看全部
TVR将技术与艺术完美融合,打造国内最好的VR游戏。
 
TVR时光机虚拟现实是北大几位优秀研究生及专业游戏行业人士共同创立,主要在做的是基于头戴式显示设备的虚拟现实内容制作,目标是打造最优秀的虚拟现实内容。主营业务《Finding》是一款轻度休闲的虚拟现实游戏(Immersive game)。它包含动作和解谜元素,配合虚拟现实设备,给玩家带来强烈的视觉冲击和前所未有的体验。
 
Web端链接 http://time-vr.com 
iPhone下载链接  https://itunes.apple.com/cn/app/id561750702
 
融资情况:
天使轮   2015.02   融资金额: ¥ 数百万 融资估值: 未披露     投资方:IDG资本
公司全称:北京时光梦幻科技有限公司  
法定代表:王世元
注册资本:28 万元 人民币
注册日期:2015-03-12
vr.png

vr2.png

他们正在36kr融资:https://rong.36kr.com/company/170680/overview
可以关注哦!

Python在生产环境都可以用来做什么?

编程 koyo 回复了问题 2 人关注 3 个回复 7120 次浏览 2015-12-14 14:45 来自相关话题

Python编码风格小结

运维 空心菜 发表了文章 0 个评论 2251 次浏览 2015-12-14 00:11 来自相关话题

一、缩进统一 缩进统一,一般可以提高我们代码的可读性,开发过程中协作统一的规范。相对于其他语言python的缩进相对要求比较严格,如果缩进不对会造成代码的错误。比如我们可以使用tab/两个空格/四个空格等作为python开发过程中的一 ...查看全部


一、缩进统一


缩进统一,一般可以提高我们代码的可读性,开发过程中协作统一的规范。相对于其他语言python的缩进相对要求比较严格,如果缩进不对会造成代码的错误。比如我们可以使用tab/两个空格/四个空格等作为python开发过程中的一个标准,但是为了合作协同我们还是以四个空格作为标准为好!
我们那些地方需要考虑缩进呢?


二、变量规范


    []标识符的第一个字符必须是字母表中的字母(大写或小写)或者一个下划线(‘ _ ’)[/][]标识符名称的其他部分可以由字母(大写或小写)、下划线(‘ _ ’)或数字(0-9)组成。[/][]标识符名称是对大小写敏感的。例如,myname和myName不是一个标识符。注意前者中的小写n和后者中的大写N。[/][]有效 标识符名称的例子有i、__my_name、name_23和a1b2_c3。[/][]无效 标识符名称的例子有2example、this is spaced out和my-name。[/]

三、注释风格

Python中单引号字符串和双引号字符串都是相同的。注意尽量避免在字符串中的反斜杠以提高可读性。
    []‘hello world!’       //单行注释[/][] “ hello , my name’s xx”   //单行注释[/][]‘’’ Hello, my name’s xx,    This is the first time to be here, it’s nice to see you guys.’’’               //多行注释[/]

Airmotionlabs移动健康先行者

科技前沿 Rock 发表了文章 0 个评论 2957 次浏览 2015-12-13 14:02 来自相关话题

生活的改变,从一个口罩开始,AURA清吸口罩正在京东众筹,改变从你开始!     ...查看全部
Airmotion.jpg

生活的改变,从一个口罩开始,AURA清吸口罩正在京东众筹,改变从你开始!
 




 

利用Python实现域名查询和whois查询

编程 空心菜 发表了文章 0 个评论 6000 次浏览 2015-12-11 23:54 来自相关话题

一、域名查询 万网提供了域名查询接口,接口采用HTTP协议: 接口URL:http://panda.www.net.cn/cgi-bin/check.cgi 接口参数:area_domain,接口参数值为标准域 ...查看全部


一、域名查询


万网提供了域名查询接口,接口采用HTTP协议:
接口URL:http://panda.www.net.cn/cgi-bin/check.cgi
接口参数:area_domain,接口参数值为标准域名,例:52bong.com
调用举例:
http://panda.www.net.cn/cgi-bin/check.cgi?area_domain=52bong.com
返回:


200
52bong.com
211 : Domain exists
返回结果说明:
200 返回码,200表示返回成功
52bong.com 表示当前查询的域名
211 : Domain exists 返回结果的原始信息,主要有以下几种

original=210 : Domain name is available 表示域名可以注册
original=211 : Domain exists 表示域名已经注册
original=212 : Domain name is invalid 表示查询的域名无效
original=213 : Time out 查询超时


Python实现


1.1 查询已经被注册的域名
>>> import urllib2
[quote]>> req=urllib2.urlopen('http://panda.www.net.cn/cgi-bin/check.cgi?area_domain=52bong.com')
>>> print (req.read().decode())
返回结果:不可用,已经被注册
domain1.png

1.2 查询没有被注册的域名
>>> req2=urllib2.urlopen('http://panda.www.net.cn/cgi-bin/check.cgi?area_domain=52bongxxx.com')
>>> print (req2.read().decode())
返回结果:可用,未被注册
domain2.png

1.3 查询不加后缀的域名
>>> req3=urllib2.urlopen('http://panda.www.net.cn/cgi-bin/check.cgi?area_domain=52bong')
>>> print (req3.read().decode())
返回结果:超时
domain3.png


二、whois查询


由于没有找到像域名查询接口那样好的API,这里直接抓取站长之家的whois查询页面(http://whois.chinaz.com/)
>>> whois = urllib2.urlopen('http://whois.chinaz.com/qclouds.com.cn')
>>> print (whois.read().decode())
在返回的结果中有这样一段html代码,这段信息就是查询的whois信息
html.png
[/quote]

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 273: ordinal not in range(128)

编程 空心菜 发表了文章 0 个评论 3759 次浏览 2015-12-11 01:06 来自相关话题

今天利用python urllib2去站长之家查询域名的whois,然后出现如下错误:>>> whois = urllib2.urlopen('http://whois.chinaz.com/qclouds.com.cn') [quote]>> p ...查看全部
今天利用python urllib2去站长之家查询域名的whois,然后出现如下错误:
>>> whois = urllib2.urlopen('http://whois.chinaz.com/qclouds.com.cn')
[quote]>> print (whois.read().decode())
Traceback (most recent call last):
File "", line 1, in
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 273: ordinal not in range(128)
原因分析:
python的str默认是ascii编码,和unicode编码冲突,就会报这个标题错误。
通过搜集网上的资料,自己多次尝试,问题总算是解决了,在代码中加上如下几句即可:
import sys
reload(sys)
sys.setdefaultencoding('utf8')
不知道还有更好的办法吗?
修复后,结果如下:
pycode.png

http://docs.python.org/howto/unicode.html  这个是python的unicode编码API文档,英文好的同学可以看一下,加深理解。
参考资料:https://groups.google.com/forum/#!topic/python-cn/9I73RUUnQPY 


混淆了 python2 里边的 str 和 unicode 数据类型


你需要的是让编码用实际编码而不是 ascii
对需要 str->unicode 的代码,可以在前边写上
import sys
reload(sys)
sys.setdefaultencoding(‘utf8′)
把 str 编码由 ascii 改为 utf8 (或 gb18030)
python3 区分了 unicode str 和 byte arrary,并且默认编码不再是 ascii[/quote]

八大持续集成工具

运维 push 发表了文章 0 个评论 12506 次浏览 2015-12-10 23:05 来自相关话题

下面依次介绍8大持续集成工具 一、Hudson Hudson 是一个可扩展的持续集成引擎,主要用于: []持续、自动地构建/测试软件项目, ...查看全部
下面依次介绍8大持续集成工具


一、Hudson


hudson.png

Hudson 是一个可扩展的持续集成引擎,主要用于:
    []持续、自动地构建/测试软件项目,如CruiseControl与DamageControl。[/][]监控一些定时执行的任务。[/]

Hudson的特性如下:
    []易于安装-只要把hudson.war部署到servlet容器,不需要数据库支持。[/][]易于配置-所有配置都是通过其提供的web界面实现。[/][]集成RSS/E-mail/IM-通过RSS发布构建结果或当构建失败时通过e-mail实时通知。[/][]生成JUnit/TestNG测试报告。[/][]分布式构建支持-Hudson能够让多台计算机一起构建/测试。[/][]文件识别- Hudson能够跟踪哪次构建生成哪些jar,哪次构建使用哪个版本的jar等。[/][]插件支持-Hudson可以通过插件扩展,你可以开发适合自己团队使用的工具。[/]

二、CruiseControl

CruiseControl.png
CruiseControl是一个针对持续构建程序(项目持续集成)的框架,它包括一个email通知的插件,Ant和各种各样的CVS工具。CruiseControl提供了一个Web接口, 可随时查看当前的编译状况和历史状况。

三、Continuum

contuion.png
Apache Continuum 是最新的 CI 服务器之一,也是值得关注的一个新进入者。Continuum 的安装和配置很简单:只要下载和释放 ZIP 文件,运行命令行程序,就可以运行了。基于 Web 的界面使得配置项目很容易。而且,还不需要安装 Web 服务器,因为 Continuum 内置了 Jetty Web 服务器。并且,Continuum 可以作为 Windows 服务运行,还在应用程序的某些部分嵌入了上下文敏感的文档,从而提供了很多帮助。
Apache Continuum的特性:
    []与Maven 2.x的紧密集成[/][]与Maven SCM的紧密集成,支持Subversion/CVS/Starteam/Clearcase/Perforce[/][]基于web的容易使用的安装和配置接口[/][]Quartz-based scheduling[/][]简单的添加新的项目工程的方法[/][]用于 integration, automation and remoting的XML-RPC interface[/][]邮件提醒和IM(即时通讯)提醒IRC/Jabber/MSN[/]

四、QuickBuild

quickbuild.png
QuickBuild 是一个持续集成和发布管理的服务器软件,它提供了一个统一的控制台用来管理这些发布的信息。

五、Bamboo

bamboo.png
Atlassian Bamboo 是一款持续集成构建服务器软件(Build Server)。
Bamboo的特点:
    []简单的用户界面 容易安装 – 顺利的话,5分钟内就可以让运行起来! 自动检测你的设置 – 如果您的Server上使用了Maven,Ant或者Java设置, Bamboo会自动检测他们; [/][]连续的日志 – 监测你的build的colour coded日志;[/][] 容易显示所有项目[/]

六、Jenkins

jenkines.png
Jenkins 的前身是 Hudson 是一个可扩展的持续集成引擎。主要用于:[list=1][]持续、自动地构建/测试软件项目,如CruiseControl与DamageControl。[/][]监控一些定时执行的任务。[/]


七、TeamCity


teamcity.png

cityteam.png
TeamCity是一款功能强大的持续集成(Continue Integration)工具,包括服务器端和客户端,目前支持Java,.Net项目开发。 TeamCity提供一系列特性可以让团队快速实现持续继承:IDE工具集成、各种消息通知、各种报表、项目的管理、分布式的编译等等,所有的这些,都是 让你的团队快速享有持续继承带来的效率提升、高质量的软件保障。


八、CI-Eye


cieye.png
CI-Eye 是一个强大的持续集成构建,无需安装和设置,CI-Eye 通过 REST API 跟很多不同的 CI 服务器交互,当前支持 Hudson, Jenkins, 以及 TeamCity. CI-Eye 在一个独立的 Web 应用中运行。

php插入数据代码优化

回复

编程 Ansible 回复了问题 1 人关注 1 个回复 4399 次浏览 2015-12-09 23:53 来自相关话题