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 sysMAX_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 = urlself.dirname = dir_nameself.secret = secretself.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:continuetry: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:raisereturn 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 osHEAD_START = 0.1 # 等待服务器启动时长
SECRET_LENGTH = 10 # 密钥长度def random_string(length):  # 定义随机密钥的函数secret = ''while length > 0:length -= 1secret += 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重新实现

Python实现简单p2p下载相关推荐

  1. 超详细python下简单快速下载opencv

    ​看了许多下载安装opencv的方法,总结出一个最高效简单的,希望一些像我这样的小白可以少踩雷(主要怕自己忘记!) python下载 大家可以到官网中选择需要的版本,官网地址 ,官网下载调试pip比较 ...

  2. python下载迅雷资源助手_python练习七—P2P下载

    最近有些事儿比较忙,python的学习就断断续续,这个练习来得比预期的晚,不过还好,不管做什么,我都希望能认真对待,认真做好每一件事. 引入 这个练习原书中称作"使用XML-RPC进行文件共 ...

  3. python socket编程 实现简单p2p聊天程序

    转载自:https://www.cnblogs.com/wuxie1989/p/7204887.html python socket编程 实现简单p2p聊天程序 目标是写一个python的p2p聊天的 ...

  4. python爬虫下载小说_用PYTHON爬虫简单爬取网络小说

    用PYTHON爬虫简单爬取网络小说. 这里是17K小说网上,随便找了一本小说,名字是<千万大奖>. 里面主要是三个函数: 1.get_download_url() 用于获取该小说的所有章节 ...

  5. 用python爬虫下载视频_使用Python编写简单网络爬虫抓取视频下载资源

    我第一次接触爬虫这东西是在今年的5月份,当时写了一个博客搜索引擎,所用到的爬虫也挺智能的,起码比电影来了这个站用到的爬虫水平高多了! 回到用Python写爬虫的话题. Python一直是我主要使用的脚 ...

  6. python使用requests库下载单张图片的简单示例

    python使用requests库下载单张图片的简单示例 简要说明 代码示例 简要说明 下载图片的核心代码如下: res = requests.get(url=img_url, headers=hea ...

  7. python实现简单的小说下载V1.0

    @[TOC] python实现简单的小说下载V1.0 需求来源于很多方面,闲来无事练手了 仅用于练习使用,不建议用在其他方面 建议下载参考对比 先来一段代码 import random import ...

  8. Python 简单爬虫下载小说txt

    Python 简单爬虫下载小说txt #第一次写爬虫代码 欢迎交流指正 我们范例爬取的对象是笔趣阁的<圣墟> (最近非常火的连载小说) ##为什么选择笔趣阁# 主要是因为笔趣阁的源代码没有 ...

  9. 【Python】PyQT5+爬虫实现简单音乐下载器

    PyQT5+爬虫实现简单音乐下载器 Qt-Designer界面设计music.ui: music.py代码实现: 采用PyUIC将music.ui转为music.py,代码如下: # -*- codi ...

  10. python写五子棋游戏下载_python实现简单五子棋游戏

    本文实例为大家分享了python实现简单五子棋游戏的具体代码,供大家参考,具体内容如下 from graphics import * from math import * import numpy a ...

最新文章

  1. 腾讯 JDK 11 正式开源,高性能、太牛逼啦!
  2. Ural 1018 (树形DP+背包+优化)
  3. 网页里显示访问的那台服务器,在web服务器中把网页放在那里,才能被访问
  4. 油管螺纹尺寸对照表_数控加工过程中,如何区分新旧螺纹牌号?
  5. 不想学python-没想到,学会Python即使不做程序员都能月入过万!
  6. Java基础 if if-else if-else if-else 三种示例
  7. react 版权问题_react使用fetch封装请求的方法-简单易懂
  8. LeetCode 1566. 重复至少 K 次且长度为 M 的模式
  9. c语言考试系统开发,基于WEB的(C语言)网络考试系统的开发与研究
  10. cvs 代码无法提交
  11. Unity3D 协程 浅谈
  12. nodejs+socket.io用nginx反向代理提示400 Bad Request及ws://…无法连接的解决方法
  13. 系统测试计划编写(四)
  14. 多余元素删除(多种代码)
  15. matlab计算卸载_安装与卸载MATLAB的一点经验
  16. SANGFOR深信服远程办公客户端EasyConnect在Windows11使用兼容性问题解决案例
  17. [SPRD] 版本修改集锦
  18. 基于高光谱成像技术结合卷积神经网络的马铃薯病害检测
  19. maven自定义插件-mojo标注和参数
  20. 微型计算机原理中BX是什么,微型计算机原理第7章答案

热门文章

  1. Win10系统如何修改无线MAC地址的几种方法
  2. 苹果微信html音乐播放,iphone 微信网页自动播放音频解决办法
  3. Ubuntu永久修改IP、临时修改IP
  4. 超给力,一键生成数据库文档-数据库表结构逆向工程
  5. JavaScript设置视频播放速度
  6. python用openpyxl模块操作Excel学习笔记
  7. 雨人系统ORA-01821,时间无法识别
  8. 刘济舟:《基于IAST交互式安全测试实践的初步探索》
  9. SpringBoot 一文搞懂Spring JPA
  10. 计算机发展史说课ppt,创新杯 计算机类 说课ppt课件.ppt