*首次实现的问题*:
1.启动交互式Python解释器是mypeer.peer函数会报错
socket.error: [Errno 10061] 表示服务器忙碌中无法与您建立联机,请稍后再试。
(前面两个要在cmd下进入文件所在的目录)
2.sceret意义何在,query就将数据读取了,只不过没有以文件形式保存下了,这时以openfile把data写入文件,fetch不就没有意义了。
流程:query查询,返回code,判断是否拥有这个文件:有,fetch来判断密码,正确,写入文件,错误,返回code=2
代码:
simple_node.py
# -*- coding:utf-8 -*-
from xmlrpclib import ServerProxy
from os.path import join, isfile
from SimpleXMLRPCServer import SimpleXMLRPCServer
from urlparse import urlparse
import sys
MAX_HiSTORY_Len = 6
ok = 1
FAIL = 2
EMPTY = ''
def getPort(url):
name = urlparse(url)[1]
parts = name.split(':')
return int(parts[-1])
class Node(object):
#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_Len:
return FAIL, EMPTY
return self._broadcast(query,history)
def hello(self,other):
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):
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):
return FAIL, EMPTY
return OK , open(name).read()
def _broadcast(self,query,history):
for other in self.known.copy():
if other in history:
continue
try:
s = ServerProxy(other)
code, data = s.query(query,history)
if code == ok:
return code , data
except:
self.known.remove(other)
return FAIL , EMPTY
def main():
url, directory, secret = sys.argv[1:]
print url,dict,secret
n = Node(url,directory, secret)
n._start()
if __name__ == '__main_':
main()
再次实现:
1.将于client.py ,url.txt放置在要共享的目录下
2.同时运行几个client.py,分配不同的端口
server:
# -*- coding:utf-8 -*-
from xmlrpclib import ServerProxy, Fault
from os.path import join, abspath, isfile
from SimpleXMLRPCServer import SimpleXMLRPCServer
from urlparse import urlparse
import sys
SimpleXMLRPCServer.allow_reuse_address = 1
MAX_HISTORY_LEN = 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 __int__(self,message="Access denied"):
Fault.__init__(self,ACCESS_DENIED,message)
def inside(dir,name):
#检查dir中是否有给定的文件名
dir = abspath(dir)
name = abspath(name)
return name.startswith(join(dir,''))
#从url中提取port,输入形式为http://...:port
def getPort(url):
name = urlparse(url)[1]
parts = name.split(':')
return int(parts[-1])
class Node(object):
#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:
code, data = self._handle(query)
except UnhandledQuery:
history = history + [self.url]
if len(history) >= MAX_HISTORY_LEN:
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 ACCESS_DENIED
result =self.query(query)
f = open(join(self.dirname,query),'w')
f.write(result)
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 UNHANDLED
if not inside(dir,name):
raise ACCESS_DENIED
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,f:
if f.faultCode == UNHANDLED: pass
else: self.known.remove(other)
except:
self.known.remove(other)
raise UnhandledQuery
def main():
url, directory, secret = sys.argv[1:]
print url,dict,secret
n = Node(url,directory, secret)
n._start()
if __name__ == '__main_':
main()
client.py
# -*- coding:utf-8 -*-
from xmlrpclib import ServerProxy, Fault
from cmd import Cmd
from random import choice
from string import lowercase
from threading import Thread
from server import Node,UNHANDLED
from time import sleep
import sys
HEAD_START = 0.1 #seconds
SECRET_LEN = 100
def randomString(length):#返回给定长度的有字母组成的随机字母串
chars = []
letters = 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_LEN)
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, f:
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()