精华内容
下载资源
问答
  • 有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者scp之类的文件传输方式只能...

    转载:http://blogread.cn/it/article/6816?f=wb1

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

       使用方法:

       首先在源服务器上面生成种子文件

    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,具体搭建方法就使用一下搜索引擎,查找一下搭建的方法!

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

    展开全文
  • 有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者scp之类的文件传输方式只能...
  • python实现一个P2P文件发布

    千次阅读 2014-03-20 23:24:38
    有时候需要大规模的部署同一个文件,例如因为方便使用systemtap这个工具定位问题,需要把手上几百台服务器同时安装kernel-debuginfo这个包,原有的方式采用一个源服务器,采用rsync或者scp之类的文件传输方式只能...

    转自http://blogread.cn/it/article/6816

    考虑到我手上的服务器逐渐的增多,有时候需要大规模的部署同一个文件,例如因为方便使用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 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  -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 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实现简单p2p下载

    2021-05-23 21:06:04
    p2p下载 P2P对等式网络又称点对点技术,是无中心...本代码使用RPC(Remote Procedure Call)远程过程调用的思路实现P2P下载,并实现绝大部分逻辑,client只是对server做一个封装。 server.py 源码 #-- coding:UTF-

    p2p下载

    • P2P对等式网络又称点对点技术,是无中心服务器、依靠用户群(peers)交换信息的互联网体系,它的作用在于,减低以往网络传输中的节点,以降低数据丢失的风险。
    • 通俗而言,P2P下载就是指数据的传输不再通过服务器,而是网络用户之间直接传递数据。
    • 简版p2p下载流程:
      在这里插入图片描述

    server

    本代码使用RPC(Remote Procedure Call)远程过程调用的思路实现P2P下载,并实现绝大部分逻辑,client只是对server做一个封装。

    server.py 源码
    #-- coding:UTF-8 --
    from xmlrpc.server import SimpleXMLRPCServer  # 用于创建服务器
    from xmlrpc.client import ServerProxy ,Fault # 用于向其它节点发出请求
    from urllib.parse import urlparse  # 用于URL解析
    from os.path import join, isfile ,exists , abspath # 用于路径处理和文件查询
    from os import mkdir
    import sys
    
    MAX_HISTORY_LENGTH = 6  # 访问链最大长度
    
    SimpleXMLRPCServer.allow_reuse_address = 1  # 保证节点服务器重启时能够立即访问
    UNHANDLED = 100  # 文件不存在的异常代码
    ACCESS_DENIED = 200  # 文件访问受限的异常代码
    
    class UnhandledQuery(Fault):  # 创建自定义异常类
        def __init__(self, message='无法处理请求!'):  # 定义构造方法
            Fault.__init__(self, UNHANDLED, message)  # 重载超类构造方法
    
    class AccessDenied(Fault):  # 创建自定义异常类
        def __init__(self, message='访问资源受限!'):  # 定义构造方法
            Fault.__init__(self, ACCESS_DENIED, message)  # 重载超类构造方法
    
    def inside(dir_path, file_path):  # 定义文件路径检查的方法
        directory = abspath(dir_path)  # 获取共享目录的绝对路径
        file = abspath(file_path)  # 获取请求资源的绝对路径
        return file.startswith(join(directory, ''))  # 返回请求资源的路径是否以共享目录路径开始
    
    def get_port(url):  # 定义获取端口号的函数
        result = urlparse(url)[1]  # 解析并获取URL中的[域名:端口号]
        port = result.split(':')[-1]  # 获取以":"进行分割后的最后一组
        return int(port)  # 转换为整数后返回
    
    class Node:
        def __init__(self, url, dir_name, secret):
            self.url = url
            self.dirname = dir_name
            self.secret = secret
            self.known = set()
    
        def _start(self):  # 定义启动服务器的方法
            server = SimpleXMLRPCServer(('', get_port(self.url)), logRequests=False)
            server.register_instance(self)  # 注册类的实例到服务器对象
            server.serve_forever()
    
        def _handle(self, filename):  # 定义处理请求的内部方法
            file_path = join(self.dirname, filename)  # 获取请求路径
            if not isfile(file_path):  # 如果路径不是一个文件
                # return FAIL, EMPTY  # 返回无效状态和空数据
                raise UnhandledQuery  # 抛出文件不存在的异常
            if not inside(self.dirname, file_path):  # 如果请求的资源不是共享目录中的资源
                raise AccessDenied  # 抛出访问资源受限异常
            return open(file_path).read()  # 未发生异常时返回读取的文件数据
            # return OK, open(file_path).read()  # 返回正常状态和读取的文件数据
    
        def _broadcast(self, filename, history):  # 定义广播的内部方法
            for other in self.known.copy():
                if other in history:
                    continue
                try:
                    server = ServerProxy(other)
                    return server.query(filename, history)
                except Fault as f:  # 如果捕获访问故障异常获取异常代码
                    if f.faultCode == UNHANDLED:  # 如果是文件不存在异常
                        pass  # 不做任何处理
                    else:  # 如果是其它故障异常
                        self.known.remove(other)  # 从已知节点列表中移除节点
                except:  # 如果捕获其它异常(非故障异常)
                    self.known.remove(other)  # 从已知节点列表中移除节点
            raise UnhandledQuery  # >>如果已知节点都未能请求到资源<<,抛出文件不存在异常。    
    
        def query(self, filename, history=[]):  # 定义接受请求的方法
            try:
                return self._handle(filename)
            except UnhandledQuery:  # 如果捕获文件不存在的异常
                history.append(self.url)
                if len(history) >= MAX_HISTORY_LENGTH:
                    raise
                return self._broadcast(filename, history)
          
        def hello(self, other):  # 定义向添加其它节点到已知节点的方法
            self.known.add(other)  # 添加其它节点到已知节点
            return OK  # 返回值是必须的
    
        def fetch(self, filename, secret):  # 定义下载的方法
            if secret != self.secret:  # 如果密钥不匹配
                raise AccessDenied  # 抛出访问资源受限异常
            result = self.query(filename)
            with open(join(self.dirname, filename), 'w') as file:
                file.write(result)
            return 0  # 必须返回非None的值
          
    def main(): 
        url, directory, secret = sys.argv[1:]
        node = Node(url, directory, secret)
        node._start()
    
    if __name__ == '__main__':   
        main()
    

    client

    客户端测试说明

    • 0.文件准备

    ① 创建多个url文件,文件内容为其他节点的地址
    ② 创建多个dir目录
    ③ 其中任一个目录下创建file文件,供其他节点下载

    • 1.登录: python client.py [urlfile] [dirname] [host:port]
    $ python3 client.py url2.txt NodeFiles02 http://127.0.0.1:7777    
    >>>                 
    
    • 2.下载: >>> fetch [filename]
    >>>fetch tt
    调用服务器代理对象的下载方法        
    
    • 3.退出: >>> exit
    >>>exit
    ------------------退出程序------------------
    
    源码cilent.py
    from xmlrpc.client import ServerProxy, Fault  # 导入服务器代理类和故障类
    from random import choice  # 导入随机选取的方法
    from string import ascii_lowercase  # 导入小写字母列表对象
    from time import sleep  # 导入延迟方法
    from server import Node, UNHANDLED  # 导入服务器中的节类和变量
    from threading import Thread  # 导入线程类
    from cmd import Cmd  # 导入命令类
    import sys  # 导入系统模块
    import os
    
    HEAD_START = 0.1 # 等待服务器启动时长
    SECRET_LENGTH = 10 # 密钥长度
    
    def random_string(length):  # 定义随机密钥的函数
        secret = ''
        while length > 0:
            length -= 1
            secret += choice(ascii_lowercase)  # 随机获取小写字母叠加到变量
        return secret
    
    # 因为要使用CMD界面,所以这个类要继承CMD类。
    class Client(Cmd):
        prompt = '>>>'  # 重写超类中的命令提示符
    
        def __init__(self, url_file, dir_name, url):  # 定义构造方法
            Cmd.__init__(self)  # 重载超类的构造方法
            self.secret = random_string(SECRET_LENGTH)  # 创建密钥变量
            node = Node(url, dir_name, self.secret)  # 创建节点对象
            thread = Thread(target=node._start)  # 在独立的线程中启动服务器
            thread.setDaemon(True)  # 将线程设置为守护线程
            thread.start()  # 启动线程
            sleep(HEAD_START)  # 等待服务器启动
            self.server = ServerProxy(url)  # 创建服务器代理对象
            for line in open(url_file):  # 读取URL文件
                self.server.hello(line.strip())  # 添加URL文件中的URL到已知节点集合
    
        # 类中对应命令的方法命名,都要以“do_”开头。
        def do_fetch(self, filename):  # 定义下载命令的方法
            try:
                self.server.fetch(filename, self.secret)  # 调用服务器代理对象的下载方法
                print('调用服务器代理对象的下载方法')
            except Fault as f:  # 捕获故障异常
                if f.faultCode != UNHANDLED:  # 如果异常代码不是未找到文件
                    pass  # 不做处理
                print('找不到文件:', filename)
    
        def do_exit(self, arg):  # 定义退出命令的方法
            print('------------------退出程序------------------')
            sys.exit()  # 系统退出
    
    def main():  # 定义主程序函数
        urlfile, dir_name, url = sys.argv[1:]  # 获取通过命令行输入的参数
        client = Client(urlfile, dir_name, url)  # 创建客户端对象
        client.cmdloop()  # 启动命令行循环执行
    
    if __name__ == '__main__':
        print('Download: >>>fetch [filename]')
        print('Exit: >>>exit')
        main()
    

    项目源自 《Python基础教程(第2版)》,案例原名为“使用XML-RPC进行文件共享”

    本文代码参考自链接,并将其中python2.7 的部分用python3.7重新实现

    展开全文
  • XML-RPC实现简单的P2P文件共享 先来个百度百科:  XML-RPC的全称是XML Remote Procedure Call,即XML(标准通用标记语言下的一个子集)远程过程调用。它是一套允许运行在不同操作系统、不同环境的程序实现基于...

    XML-RPC实现简单的P2P文件共享

    先来个百度百科:

          XML-RPC的全称是XML Remote Procedure Call,即XML(标准通用标记语言下的一个子集)远程过程调用。它是一套允许运行在不同操作系统、不同环境的程序实现基于Internet过程调用的规范和一系列的实现。这种远程过程调用使用http作为传输协议,XML作为传送信息的编码格式。Xml-Rpc的定义尽可能的保持了简单,但同时能够传送、处理、返回复杂的数据结构。这个过程也被大家称为“分布式计算”。

     

    学习资料地址:

    https://docs.python.org/3/library/xmlrpc.html

    https://www.the5fire.com/python-project8-xml-rpc.html

     

    下面是测试例子:环境 Python 3.6 [版本小于3.x需改更改部分代码]

    服务端

    from xmlrpc.server import SimpleXMLRPCServer
    s = SimpleXMLRPCServer(("",4242))
    def twice(x):
        return x*2
    s.register_function(twice) 
    s.serve_forever() 

    客户端

    import xmlrpc.client
    s = xmlrpc.client.ServerProxy('http://localhost:4242')
    print(s.twice(2))

    执行结果

     

    然后步入正题,写一个文件共享的例子(python 3.6):

    例子很简单,详情看注释。

     

    Server.py

    from xmlrpc.server import SimpleXMLRPCServer
    from xmlrpc.client import ServerProxy,Fault
    from os.path import join,abspath ,isfile
    import sys
    import urllib
     
     
    SimpleXMLRPCServer.allow_reuse_address = 1
    MAX_HISTORY_LENGTH = 6
     
    UNHANDLED    = 100
    ACCESS_ENIED = 200
     
    class UnhandledQuery(Fault):
        def __init__(self ,message="Couldn't handle the query"):
            Fault.__init__(self ,UNHANDLED ,message)
     
    class AccessDenied(Fault):
        def __init__(self,message="Access denied"):
            Fault.__init__(self ,ACCESS_ENIED ,message)
     
    def inside(dir ,name):
        dir = abspath(dir)
        name = abspath(name)
        return name.startswith(join(dir ,''))
     
    def getPort(url):
        name = urllib.parse.urlparse(url)[1]
        patrs = name.split(':')
        return int(patrs[-1])  
     
    class Node:
        def __init__(self ,url ,dirname ,secret):
            self.url = url
            self.dirname = dirname
            self.secret = secret
            self.known = set()
        def query(self ,query ,history=[]):
            try:
                return self._handle(query)
            except UnhandledQuery:
                history = history + [self.url]
                if len(history) >= MAX_HISTORY_LENGTH:raise
                return self._broadcast(query ,history)
        def hello(self ,other):
            self.known.add(other)
            return 0
        def fetch(self ,query ,secret):
            if secret != self.secret: raise AccessDenied
            result = self.query(query)
            f = open(join(self.dirname,query) ,'w')
            f.write(result)
            f.close()
            return 0
        def _start(self):
            s = SimpleXMLRPCServer(("" ,getPort(self.url)),logRequests=False)
            s.register_instance(self)
            s.serve_forever()
        def _handle(self ,query):
            dir = self.dirname
            name = join(dir ,query)
            if not isfile(name) : raise UnhandledQuery
            if not inside(dir ,name): raise AccessDenied
            return open(name).read()
        def _broadcast(self ,query ,history):
            for other in self.known.copy():
                if other in history : continue
                try:
                    s = ServerProxy(other)
                    return s.query(query ,history)
                except Fault:
                    self.known.remove(other)
                    #if Fault.faultCode == UNHANDLED: pass
                    #else: self.known.remove(other)
                except:
                    self.known.remove(other)
            raise UnhandledQuery
    def main():
        url,directory ,secret = sys.argv[1:]
        n = Node(url ,directory ,secret)
        n._start()
    if __name__ == '__main__' : main()


    Client.py

    from xmlrpc.client import ServerProxy,Fault
    from cmd import Cmd
    from random import choice
    from string import ascii_lowercase
    from server import Node,UNHANDLED
    from threading import Thread
    from time import sleep
    import sys
     
    HEAD_START = 0.1 # Seconds
    SECRET_LENFGTH = 100
     
    def randomString(length):
        chars = []
        letters = ascii_lowercase[:26]
        while length > 0:
            length -= 1
            chars.append(choice(letters))
        return ''.join(chars)
     
    class Client(Cmd):
        prompt = '> '
        def __init__(self ,url ,dirname ,urlfile):
            Cmd.__init__(self)
            self.secret = randomString(SECRET_LENFGTH)
            n = Node(url ,dirname ,self.secret)
            t = Thread(target=n._start)
            t.setDaemon(1)
            t.start()
            sleep(HEAD_START)
            self.server = ServerProxy(url)
            for line in open(urlfile):
                line = line.strip()
                self.server.hello(line)
        def do_fetch(self ,arg):
            try:
                self.server.fetch(arg ,self.secret)
            except Fault:
                #if f.faultCode != UNHANDLED : raise
                print("Couldn't find the file"+arg)
        def do_exit(self ,arg):
            print
            sys.exit()
        do_EOF = do_exit
     
    def main():
        urlfile,directory,url = sys.argv[1:]
        client = Client(url ,directory ,urlfile)
        client.cmdloop()
    if __name__ == '__main__' : main()

    屡下上面代码工作流程,主要分为两部分,service和Client,service主要是维护一些节点信息,Client主要是用于当前用户发送请求和交互的地方。

    入口是从Client开始,主函数进来接受几个参数:

    (1)Urlfile.txt 路径,这个是一个文件,里面存着一些其他节点的链接url和端口,模拟当前节点用户的”伙伴”,如果把所有节点看成一张有向图的话,A->B A->c A->D 那么A节点里的这个utlfile里存的就是BCD的链接信息。当然这里是为了模拟,实际情况可能是在某个位置获取,或者是在运行过程中不断积累的。

    (2)第二个参数directory路径,也就是指向一个路径,当做是当前节点的共享文件夹。

    (3)最后一个url参数,是本地service的node节点建立服务的url和端口,比如要开一个本地端口2333的Node节点服务,直接传递http://localhost:2333。

     

    得到参数之后,是先进入客户端client类,构造函数里面先随机生成一个本地密码,然后在创建一个Node节点,把Node节点的_start作为线程函数创建线程(_start是创建服务器节点并且开启监听),然后在创建一个ServerProxy链接自己机器上这个Node节点服务,调用服务的Hello函数把urlfile里面的伙伴信息都hello进去(hello是存的链接信息表)。至此Client的初始化完成。

        Client初始化之后,就cmdloop了,相关连的韩式Client里面的两个函数do_fetch和exit。Fetch函数获取文件。客户端通过调用这个发送获取文件的命令。这里阿敏直接是请求本地Node节点的fetch函数,本地节点这个函数接到命令后是先判断下密码(其实觉得这个密码就是摆设),然后开始进入query函数来查询文件,query函数里面是先尝试一波看看文件在不在本地,如果不在的话就判断下是不是达到请求限制了,如果没到的话就把自己的朋友链拿出来,直接调广播告调用朋友们的query函数(RPC),朋友的query也是这个逻辑,本地有就直接返回结果,没有继续调用朋友的朋友。这个地方如果抽象成图的话就是深度优先搜索遍历(DFS),当然可以想办法BFS。这样最后调查结果会回溯到发起问题的起始节点,也就是最开始客户端调用的fetch函数,如果找到文件就保存起来,没找都就输出相关提示就行了。这个就是这个XMP-PRC(上面代码) 简单例子的实现思路。最后是测试路程。


    测试步骤如下

        首先需要建立两个文件夹,A和C,C文件夹里面创建一个文件,B.txt,在A和C所在文件夹中建立urlsA.txt和urlsC.txt文件。里面在urlsA.txt中写入:http://localhost:4243,然后开启两个命令行

     


    打开一个cmd窗口A

         python client.py urlsA.txt A http://localhost:4242 

         fetch B.txt

    执行完这两条命令,应该是看到的文件无法找到

     

    再次打开一个窗口B(第一个窗口不关)

        python client.py urls C.txt C http://localhost:4243

        fetch B.txt

    执行完两条命令,没有任何输出,说明文件在这个地方是能找到的。

     

        此时再次回头在第一个打开的窗口中查找B fetch B.txt 发现还是没有找到,讲道理此时应该可以的,因为第一个里面有第二个的通讯地址。

        把上面两个node反过来启动就可以了,因为在A启动的时候,链接B,但是B不在,A以为B下线了,就把B从列表里移出去了。

    反过来执行,会发现A可以成功吧文件下载到A文件夹下。

        上面所有代码就是个测试例子,有很多细节没有处理,可以根据实际情况多改改。好好熟悉熟悉XML-RPC以及P2P的基本原理。

     

     

     

     

    展开全文
  • python-p2p 一个简单的基于python3 p2p 该代码为对等体之间的信息交换提供了一个简单的网络结构。 用法 安装要求: pip3 install -r requirements.txt 注意:已在python 3.6上测试 启动节点: pyton3 main.py
  • 网狼 P2P文件传输管理器
  • 利用python实现局域网内的文件传输 当前目录地址栏我们输入cmd,按回车就自动进入当前目录,这点小技巧尤其方便,省的我们在一级一级去记忆那么繁琐的目录了 接下来我们输入命令,默认端口是8000,我这里指定了...
  • P2P文件共享 基于python的文件(包括大文件)共享系统。 系统简介 实现了P2P分布式文件共享系统,方便用户之间完成完整的去中心化文件传输,包括文本,音乐,视频等等。用户中断即是资源提供者,又是资源获取者,...
  • 基于python实现的CS通信和P2P通信

    千次阅读 2019-07-24 19:12:29
    一、实验要求 C/S通信实现要求 ... 不采用方式,自定义通信协议,传输文件要足够大(例如:一个视频文件P2P通信实验要求 为每个peer开发服务器程序、客户端程序 每个peer上线后,向服务器注册...
  • 通过本地网络进行P2P文件传输。 本地套接字是一个愚蠢的项目代号,用于通过同一WiFi与他人共享文件。 使命宣言 创建一个快速,开放,安全和跨平台的解决方案,与周围的人共享文件。 安装 在Windows / Mac / Linux...
  • 实现一个简单的p2p文件传输,主要解决NAT穿透问题,使用tcp协议传输。 NAT背景介绍 简介 NAT(Network Address Translation ,网络地址转换) 是一种广泛应用的解决IP 短缺的有效方法, NAT 将内网地址转和端口号...
  • 一、实验要求 C/S通信实现要求 两台计算机分别模拟服务器、客户端 通过编程实现服务器端、客户端程序Socket,Client。... 不采用方式,自定义通信协议,传输文件要足够大(例如:一个视频文件) ...
  • udp_P2P即时视频文件传输
  • 这个练习项目来自《Python基础教程(第2版)》,案例原名为“使用XML-RPC进行文件共享”。 原文是基于Pyhton2.7,其中使用的一些模块在Python3中已经发生改变,这里使用Python3完成这个练习项目 。 练习过程分为两...
  • 基于pythonp2p 贷后指标全自动日报制作 author : sunyaowu begin_time : 2018年8月27日 end_time : 2018年9月7日 说明 :贷后指标,包括贷放、逾期、清理等内容。 文章目录 基于pythonp2p 贷...
  • python实现的简单加密通信,采用pycrypto加密模块实现
  • 目录第一种 HTTP服务第二种 FTP服务功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容...python -m SimpleHTTPServer
  • 一个python写的p2p 文件传输和数据交流的程序 花了三天从零开始python写出的,要是有不规范的地方还请见谅 使用了socket套接字的知识 threading多线程的知识 github地址:https://github.com/lokey-t/p2p-socket- ...
  • 分布式分散式文件存储,用于具有git类版本控制的工作组。 如何运行: python3 Main.py -h 测试: 光盘P2PFileExchange python3 -m unittest discover-开始目录=测试--pattern = *。py 需要CPython解释器3.4 ...
  • python练习七—P2P下载

    2018-02-28 09:05:04
    这个练习原书中称作“使用XML-RPC进行文件共享”,题目是从使用的技术介绍的,做完这个练习之后我觉得最终其实实现的是一个迅雷的雏形——一个P2P下载器。当然了实际使用中的下载工具远远比这个要复杂,包括断点续...
  • Python 实现Ethernet/IP 通信

    千次阅读 2018-12-11 13:43:20
    EtherNet / IP是为了在以太网中使用CIP协议而进行的封装.EtherNet / IP的CIP帧封装了命令,数据点和消息等信息.CIP帧包括CIP设备配置文件数据包的其余部分是以太网/ IP帧,CIP帧通过它们在以太网上传输。EIP一般使用...
  • 基于python rpc的简单文件共享

    千次阅读 2017-04-16 12:38:24
    本文记录了一个使用rpc进行简单文件共享的程序,仅用于p2p原理学习,关于这段代码中的异常处理等部分还有很多值得学习的地方。 server.py# -*- coding=utf-8 -*-from xmlrpclib import ServerProxy, Fault from ...
  • 基于UDP打洞(内网穿透)实现P2P聊天程序代码及原理分析 代码链接https://github.com/laike9m/PyPunchP2P ps:我分析的是别人的代码 1:运行 假设服务端的IP是192.168.88.100,监听5678端口 python server.py 5678 ...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • 编写socket调用类似于FTP实现文件传输,MD5比对。 Socket编程实现文件传输 要求:FTP Server 1、读取文件名2、检测文件是否存在3、打开文件4、检测文件大小5、发送文件大小给客户端6、等客户端确认7、开始边读...
  • 一般情况下,在运维多台服务器的时候,使用Ansible来完成文件的分发和命令的执行。但如果运维的机器数量多,而且内网...那么对于这种大文件的大规模分发,能想到的好的解决方案就是利用P2P网络实现,节省带宽,提高...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,830
精华内容 1,932
关键字:

python实现p2p文件传输

python 订阅