python基础 27章 使用XML_RPC进行文件共享

# *-*coding:utf-8 *-*


#python 3简单的Node实现 (simple_node.py)
from xmlrpc.client import ServerProxy
from os.path import join, isfile
from xmlrpc.server import SimpleXMLRPCServer
from urllib.parse import urlparse
import sys


def getPort(url):
'从url中获取节点'
name = urlparse(url)[1]
parts = name.split(':')
return int(parts[-1])


MAX_HISTORY_LENGTH = 6
OK = 1
FAIL = 2
EMPTY = ''


class Node:
"""
p2p中的网络节点
"""
def __init__(self, url, dirname, secret):
self.url = url
self.dirname = dirname
self.secret = secret
self.known = set()

def query(self, query, history=[]):
"""
查询文件可能向其他已知节点求助, 将文件作为字符串返回
"""
code, data = self._handle(query)
if code == OK:
return code, data
else:
history = history + [self.url]
if len(history) >= MAX_HISTORY_LENGTH:
return FAIL, EMPTY
return self._broadcast(query, history)

def hello(self, other):
"""
将节点添加到self.known中
"""
self.known.add(other)
return OK

def fetch(self, query, secret):
"""
寻找文件并且下载当前节点目录
"""
if secret != self.secret: return FAIL
code, data = self.query(query)
if code == OK:
f = open(join(self.dirname, query), 'w')
f.write(data)
f.close()
return OK
else:
return FAIL

def _start(self):
"""用于启动XML_PRC服务器"""
s = SimpleXMLRPCServer(("", getPort(self.url)), logRequests=True)
s.register_instance(self)
s.serve_forever()

def _handle(self, query):
"""isfile判断路径是否存在,如果存在返回OK和读取内容"""
dir = self.dirname
name = join(dir, query)
if not isfile(name): return FAIL, EMPTY
return OK, open(name).read()

def _broadcast(self, query, history):
"""
用hello方法加入的self.known中url查询文件
"""
for other in self.known.copy():
if other in history: return FAIL, EMPTY
try:
s = ServerProxy(other)
code, data = s.query(query)
if code == OK:
return  code, data
except:
self.known.remove(other)
return FAIL, EMPTY


def main():
url, dirname, secret = sys.argv[1:]
n = Node(url, dirname, secret)
n._start()


if __name__ == '__main__':
main()


"""
xmlrpc.server, xmlrpc.client, urllib.parse,cmd文档
https://docs.python.org/3/library/xmlrpc.server.html
https://docs.python.org/3/library/xmlrpc.client.html
https://docs.python.org/3/library/urllib.parse.html
https://docs.python.org/3/library/cmd.html


运行节点
$: python simple_node.py http://localhost:4242


连接
>>> from xmlrpc.client import *
>>> one = ServerProxy('http:localhost:4242')
>>> one.query('test.txt') 调用服务器的query方法

"""

------------------------------------------------------------------------------------------------------------

#!/usr/bin/python
# *-*coding:utf-8 *-*


#pyhton3 新的Node实现(server.py)
from xmlrpc.client import ServerProxy, Fault, Binary
#from xmlrpclib import ServerProxy, Fault


from os.path import join, abspath, isfile
from xmlrpc.server import SimpleXMLRPCServer
#from SimpleXMLRPCServer import SimpleXMLRPCServer


from urllib.parse import urlparse
#from urlparse import urlparse
import sys


#SimpleXMLRPCServer.allow_reuse_address = 1 #源文件已经是True
MAX_HISTORY_LENGTH = 6
UNHANDLED = 100
ACCESS_DENIED = 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_DENIED, message)


def inside(dir, name):
"""
检查给定的目录中是否有给定的文件名
"""
dir = abspath(dir)
name = abspath(name)
return name.startswith(join(dir, ''))


def getPort(url):
"""
从url中提取端口
"""
name = urlparse(url)[1]
parts = name.split(':')
return int(parts[-1])

class Node:
"""
p2p网络中的节点
"""
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):
"""
用于将节点介绍给其他节点
当前节点使用hello将其他节点添加到self.known集合中,调用query-broadcast
使用其他节点打开下载文件
"""
self.known.add(other)
return 0

def fetch(self, query, secret):
"""
节点找到文件并且下载
open打开文件写入数据
"""
if secret != self.secret: raise AccessDenied
result = self.query(query)
#f = open(join(self.dirname, query), 'w')
#f.write(result)
#传输大的文件图片视频
f = open(join(self.dirname, query), 'wb')
f.write(result.data)
f.close()
return 0

def _start(self):
"""用于启动XML_RPC服务器, 将实例注册"""
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
#使用Binary函数传输图片视频
return Binary(open(name, 'rb').read())
#return open(name).read()

def _broadcast(self, query, history):
"""
用于将查询广播到所有的已知节点.
也就是当前节点用helle方法将其他节点添加到self.known中
用其他节点创建client,然后返回查询值
"""
for other in self.known.copy():
if other in history: continue
try:
s = ServerProxy(other)
return s.query(query, history)


except Fault as f:
if f.faultCode == UNHANDLED: pass
else: self.known.remove(other)


#except Exception as e:
except:
self.known.remove(other)
raise UnhandledQuery

def main():
url, dirname, secret = sys.argv[1:]
n = Node(url, dirname, secret)
n._start()


if __name__ == '__main__':
main()

----------------------------------------------------------------------------------------------------

#!/usr/bin/python
# *-*coding:utf-8 *-*


#python3 新的Node控制器界面(client.py)


#from xmlrpclib import ServerProxy, Fault
from xmlrpc.client import ServerProxy, Fault


from cmd import Cmd
from random import choice


#from string import lowercase
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_LENGTH = 100


def randomString(length):
"""
返回给定长度的由字母组成的随机字符串
"""
chars = []
#letters = lowercase[:26]
letters = ascii_lowercase[:26]
while length > 0:
length -= 1
chars.append(choice(letters))
return ''.join(chars)


class Client(Cmd):
"""
Node类的简单的基于文本的界面
"""
promt = '>'

def __init__(self, url, dirname, urlfile):
"""
设定url, dirname和urlfile,并且在单独的线程中启动Node服务器
"""
Cmd.__init__(self)
self.secret = randomString(SECRET_LENGTH)
n = Node(url, dirname, self.secret)
t = Thread(target=n._start)
t.setDaemon(1)
t.start()
#停0.1秒让服务器先启动
sleep(HEAD_START)
self.server = ServerProxy(url)
for line in open(urlfile, 'r'):
line = line.strip()
self.server.hello(line)



def do_fetch(self, arg):
"""调用服务器的fetch方法"""
try:
self.server.fetch(arg, self.secret)
except Fault as f:
if f.faultCode != UNHANDLED: raise
print("Couldn't find the file", arg, f.faultCode, UNHANDLED, f)

def do_exit(self, arg):
"""退出程序 打印空行处于美观考虑..."""
print()
sys.exit()

do_EOF = do_exit #EoF与'exit'同义


#获取命令输入,添加到client中
def main():
urlfile, directory, url = sys.argv[1:]
client = Client(url, directory, urlfile)
client.cmdloop()


if __name__ == '__main__':
main()


"""
命令行 $ python client.py ~/urls.txt ~/directory/  http://localhost:4242
$ python client.py ~/urls.txt ~/directory/  http://localhost:4243

urls.txt中每一行都包括程序所知道的其他节点的url地址
初始时4242端口的directory中没有要查询的文件。如果只运行4242命令行调用do_fetch,_broadcast的第二个except捕捉Connection refused错误。do_fetch返回Couldn'file,原因是4243的节点服务器还没有启动。
只运行4242不运行4243就会返回返回错误




"""

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值