Python练习3-XML-RPC实现简单的P2P文件共享
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练习3-XML-RPC实现简单的P2P文件共享的更多相关文章
- 用 ElementTree 在 Python 中解析 XML
用 ElementTree 在 Python 中解析 XML 原文: http://eli.thegreenplace.net/2012/03/15/processing-xml-in-python- ...
- python标准库xml.etree.ElementTree的bug
使用python生成或者解析xml的方法用的最多的可能就数python标准库xml.etree.ElementTree和lxml了,在某些环境下使用xml.etree.ElementTree更方便一些 ...
- [python标准库]XML模块
1.什么是XML XML是可扩展标记语言(Extensible Markup Language)的缩写,其中的 标记(markup)是关键部分.您可以创建内容,然后使用限定标记标记它,从而使每个单词. ...
- 什么是XML RPC?
# -*- coding: cp936 -*- #python 27 #xiaodeng #什么是XML RPC? #中文叫:远程过程调用 #使用http协议做传输协议的rpc机制,使用xml文本的方 ...
- Python模块 shelve xml configparser hashlib
常用模块1. shelve 一个字典对象模块 自动序列化2.xml 是一个文件格式 写配置文件或数据交换 <a name="hades">123</a>3. ...
- 一文综述python读写csv xml json文件各种骚操作
Python优越的灵活性和易用性使其成为最受欢迎的编程语言之一,尤其是对数据科学家而言.这在很大程度上是因为使用Python处理大型数据集是很简单的一件事情. 如今,每家科技公司都在制定数据战略. ...
- 【Hadoop离线基础总结】zookeeper的介绍以及集群环境搭建、网络编程和RPC的简单了解
ZooKeeper的介绍以及集群环境搭建.网络编程和RPC的简单了解 ZooKeeper介绍 概述 ZooKeeper是一个分布式协调服务的开源框架,主要用来解决分布式集群中应用系统的一致性问题.例如 ...
- 完成一段简单的Python程序,用于实现一个简单的加减乘除计算器功能
#!/bin/usr/env python#coding=utf-8'''完成一段简单的Python程序,用于实现一个简单的加减乘除计算器功能'''try: a=int(raw_input(" ...
- 在python中处理XML
XML是实现不同语言或程序之间进行数据交换的协议,XML文件格式如下: <data> <country name="Liechtenstein"> < ...
随机推荐
- Windows-Redis占用C盘系统空间
发现redis在电脑死机蓝屏的情况下,就是非正常退出redis会导致redis的缓存文件不会回收,占用系统空间, 下次在启动的时候,会再次创建一个10G多的缓存文件,极度占用磁盘空间. 现说明解决办法 ...
- Azure Front Door(二)对后端 VM 进行负载均衡
一,引言 上一篇我们讲到通过 Azure Front Door 为我们的 Azure App Service 提供流量转发,而整个 Azure Front Door 在添加后端池的时候可选的后端类型是 ...
- weblogic之cve-2015-4852分析(重写)
前言 有时间打算分析weblogic历史漏洞,但是又要面试啥的,没空.又刚好最近面试会问weblogic反序列化.具体啥时候分析weblogic反序列化,可能会在护网后,或者我开学了再分析.期间可能我 ...
- apk动态调试
android.os.Debug类提供了isDebuggerConnected()用于检测是否有调试器链接: AndroidManifest的application节点中加入android:debug ...
- c语言跨文件调用函数中声明的变量
转载:weixin_33885253 变量的作用域 变量根据其作用域有全局变量和局部变量之分.全局变量作用域是整个文件,并且可以使用关键字extern达到跨文件调用的目的.但是局部变量值作用于它当前所 ...
- 【牛客网】数据库SQL实战(题解)
1.查找最晚入职员工的所有信息 [题解] hire_date可能存在重复值,所以需要找到hire_date的最大值,然后再筛选,才能hire_date最晚的记录都筛选出来. [代码] 1 SELECT ...
- 攻防世界 reverse 进阶 -gametime
19.gametime csaw-ctf-2016-quals 这是一个小游戏,挺有意思的 's'-->' ' 'x'-->'x' 'm'-->'m' 观察流程,发现检验函 ...
- FutureTask核心源码分析
本文主要介绍FutureTask中的核心方法,如果有错误,欢迎大家指出! 首先我们看一下在java中FutureTask的组织关系 我们看一下FutureTask中关键的成员变量以及其构造方法 //表 ...
- 小白的第一次sql实战
去年发的有一篇sql注入忘记粘贴过来了,今天想起了就fuzz过来一下 有id尝试sql注入 找这种sql注入的站用sql检索就行了,但是最好挂代理用谷歌搜索,百度的话搜sql注入的很多被别人打过了,导 ...
- Python基础(十五):Python的3种字符串格式化,做个超全对比!
有时候,为了更方便.灵活的运用字符串.在Python中,正好有3种方式,支持格式化字符串的输出 . 3种字符串格式化工具的简单介绍 python2.5版本之前,我们使用的是老式字符串格式化输出%s. ...