linux 下 rpc python 实例之使用XML-RPC进行远程文件共享
这是个不错的练习,使用python开发P2P程序,或许通过这个我们可以自己搞出来一个P2P下载工具,类似于迅雷。XML-RPC是一个远程过程调用(remote procedure call,RPC)的分布式计算协议,通过XML将调用函数封装,并使用HTTP协议作为传送机制[摘自维基百科]
1.先做一个小小的尝试: 首先进入命令行,输入vim pythonServer.py,然后输入一下代码:
from simpleXMLRPCServerr import SimpleXMLRPCServerr
s = SimpleXMLRPCServer(("",4242)) #默认为本机
def twice(x):
return x*x s.register_function(twice) #向服务器添加功能
s.serve_forever() #启动服务器
2. 输入python,打开shell 交互命令行
from xmlrpclib import ServerProxy
s = ServerProxy('http://localhost:4242')
s.twice(6) #通过ServerProxy调用远程的方法,
3. 开始文件共享完整代码:
3.1 服务器端Server.py
#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_LENGTH = 6 UNHANDLED = 100
ACCESS_DENIED = 200 class UnhandledQuery(Fault):
'''
that's show can't handle the query exception
'''
def __init__(self,message="Couldn't handle the query"):
Fault.__init__(self, UNHANDLED, message) class AccessDenied(Fault):
'''
when user try to access the forbiden resources raise exception
'''
def __init__(self, message="Access denied"):
Fault.__init__(self, ACCESS_DENIED, message) def inside(dir,name):
'''
check the dir that user defined is contain the filename the user given
'''
dir = abspath(dir)
name = abspath(name)
return name.startswith(join(dir,''))
def getPort(url):
'''
get the port num from the url
'''
name = urlparse(url)[1]
parts = name.split(':')
return int(parts[-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
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, 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:]
n = Node(url,directory,secret)
n._start() if __name__ == '__main__':
main()
首先来看上面的几个常量设置: SimpleXMLRPCServer.allow_reuse_address表示,其所占用的端口可以重用,即如果你强制关闭node server之后再次重启,不会出现端口被占用的情况。
MAX_HISTORY_LENGTH = 6 这个是设置最大的节点长度,因为不能让让节点无休止的搜索下去。
UNHANDLED = 100 ACCESS_DENIED = 200 这俩就是返回码。
然后再来看个node节点的具体流程。 这个段代码的流程这这样的,首先,启动供远程调用的服务器,调用的接口就是Node类。在Node类中有三个方法供远程调用的,一个是hello,一个是fetch还有一个query。hello 这个方法就是添加邻节点信息到当前节点中。而fetch则是用来获取数据的方法,query是节点之间用来交互的。
在fetch方法中,首先判断密码是否正确,然后通过调用自己的query方法查找数据。我们来看query方法,这个方法中,先是调用私有方法_handle本地查找,如果没找到,那么在通过_broadcast接口在所有已知节点中发送广播,这里要注意histroy,每次广播都会传递history这个参数,这个参数的作用有二:一是、防止往重复的节点中发送广播;二是、限制当前所有链接节点的长度。
理解了一个node server的基础功能之后,再来看对server进行管理的控制类代码。
3.2 客户端代码 Client.py
#coding=utf-8 from xmlrpclib import ServerProxy, Fault
from cmd import Cmd
from random import choice
from string import lowercase
from server import Node,UNHANDLED #引入前面的server
from threading import Thread
from time import sleep import sys HEAD_START = 0.1
SECRET_LENGTH = 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_LENGTH)
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):
sys.exit() do_EOR = do_exit def main():
urlfile, directory, url = sys.argv[1:]
client = Client(url, directory, urlfile)
client.cmdloop() if __name__ == '__main__':
main()
来分析一下这段代码,前面的参数就不看了,很好理解,一开始有一个随机生成密码的函数,做什么用的呢?主要是用来防止别人非法调用该控制所控制的node server的。这密码 我们也不用记,因为我们有client的合法使用权。呵呵。
这段代码的总体作用就是为你提供一个可视的命令行的界面,通过继承cmd这个类,来解析你输入的命令,比如程序运行之后,出现命令提示符,你输入fetch,那么它会调用到do_fetch这个方法中来,并把参数传递进来。do_fetch这个方法的所用就是调用node server中的fetch方法,获取资源。另外的一个do_exit很好理解,就是接受exit命令退出程序。
在程序初始化的时候,还有一点需要注意,就是它会读取你urlfile参数传递的文件中的数据,这个里面放的是节点的url地址。读取之后程序会把这些地址加到相邻节点中,供以后访问。不过这个程序还有些不完善的地方就是在程序运行时,如果你修改了url配置的文件,他不会读取你新添加的节点url。不过这个修改很简单,把获取url的代码放到do_fetch中就行了。
在运行程序之前还有一些工作要做。 首先需要建立两个文件夹,A和C,C文件夹里面创建一个文件,B.txt,在A和C所在文件夹中建立urlsA.txt和urlsC.txt文件。里面在urlsA.txt中写入:http://localhost:4243,然后开启两个命令行,
第一个输入:
python client.py urlsA.txt A http://localhost:4242
回车,是不是出来提示符了。输入fetch B.txt回车,看到提示Couldn't find the file B.txt。、
然后在第二个命令行中输入
python client.py urlsC.txt C http://localhost:4243
回车。同样输入fetch B.txt回车,是不是没反应。说明该文件存在。接在在第一个命令行中再次输入fetch B.txt看,是否还是提示没找到文件,如果你对代码根据我上面的建议进行了修改的话,就不会出现错误了,如果没有修改,此时你需要把输入exit退出程序,再次重启,然后在fetch B.txt,然后到A文件夹下查看一下,看是不是把B.txt下载到你的文件夹中了。
PS:上面的程序只能传输文本文件,大文件或者其他格式的文件无法传输,刚才研究了一下,使用xmlrpclib这个库中的Binary函数即可,具体使用访问为: 先引入xmlrpclib,import xmlrpclib 在server类的的_handle方法中最后返回的那句代码return open(name).read() 修改为 return xmlrpclib.Binary(open(name,'rb').read()) 再把fetch方法中的f.write(result)修改为f.write(result.data) 另外这句话前面的那个写文件的方式要改为wb。
【转自】 python项目练习八:使用XML-RPC进行远程文件共享 感谢楼主!
参考:
linux 下 rpc python 实例之使用XML-RPC进行远程文件共享的更多相关文章
- linux下安装python
在Linux下安装Python的操作相当简单,按如下步骤操作即可: 命令: wget https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tgzt ...
- Linux 下安装python软件包(pip、nose、virtualenv、distribute )
新手刚开始学习Python,目前学习<笨方法学python>ing- 在学习习题46时需要安装几个软件包:pip.nose.virtualenv.distribute !在此记录Linux ...
- linux下安装python linux下一些常用的命令
注意 ubuntukylin-14.04.2-desktop-amd64 自带python2.7.6 这个说的比较详细 http://wenku.baidu.com/link?url=gaeFcQrc ...
- 在Linux下如何用Shell脚本读写XML?现有一个config.xml(转)
在Linux下如何用Shell脚本读写XML?现有一个config.xml <?xml version="1.0" encoding="UTF-8"?&g ...
- linux下socket编程实例
linux下socket编程实例一.基本socket函数Linux系统是通过提供套接字(socket)来进行网络编程的.网络的socket数据传输是一种特殊的I/O,socket也是一种文件描述符.s ...
- Linux下升级Python到3.5.2版本
原文出处:https://www.cnblogs.com/tssc/p/7762998.html 本文主要介绍在Linux(CentOS)下将Python的版本升级为3.5.2的方法 众所周知,在20 ...
- linux下配置python环境 django创建helloworld项目
linux下配置python环境 1.linux下安装python3 a. 准备编译环境(环境如果不对的话,可能遇到各种问题,比如wget无法下载https链接的文件) yum groupinstal ...
- linux下搭建python机器学习环境
前言 在 linux 下搭建 python 机器学习环境还是比较容易的,考虑到包依赖的问题,最好建立一个虚拟环境作为机器学习工作环境,在建立的虚拟环境中,再安装各种需要的包,主要有以下6个(这是看这个 ...
- Python3.x:Linux下退出python命令行
Python3.x:Linux下退出python命令行 退出命令: quit() #或者 exit() #或者 Ctrl-D
- Linux 下安装Python报错:zlib not available
问题描述: 在Linux下安装Python时出现一个错误:zipimport.ZipImportError: can't decompress data; zlib not available 详细错 ...
随机推荐
- <constant name="struts.devMode" value="false" />
在开发中,我们常常会遇到<constant name="struts.devMode" value="false" />,这是struts2的特性, ...
- MySQL主从数据一致性问题修复
MySQL主从数据一致性问题修复 前面,我们使用pt-table-checksum 可以检测出主从数据是否一致的问题.发现问题后,我们怎么解决这些问题,也是我们必须要会的技能. 修复主从数据一致性问题 ...
- OC基础:内存(进阶):retain.copy.assign的实现原理 分类: ios学习 OC 2015-06-26 17:36 58人阅读 评论(0) 收藏
遍历构造器的内存管理 a.遍历构造器方法内部使用autorelease释放对象 b.通过遍历构造器生成的对象.不用释放. 内存的管理总结 1.想占用某个对象的时候,要让它的引用计数器+1(retain ...
- SVM的新理解
svm导出的原始问题然后利用KKT条件,为何还需要对偶空间? 一方面,实际上KKT条件怎么得到的?KKT条件的推导是:svm原始问题->极大极小问题(先算极小这步,但极小这步中α是有约束的,不好 ...
- UNIMRCP 代码走读
基于UNIMRCP1.5.0的代码走读 与 填坑记录 1. server启动配置加载 入口:unimrcp_server.c static apt_bool_t unimrcp_server_load ...
- 使用Django+MySQL+Apache+Linux创建简单的博客
本教程基于慕课网<Django入门与实践>编写,基于CentOS 7 基础知识 什么是django? Django是一个基于Python的高级Web开发框架, 特点:高效,快速,高度集成( ...
- [LeetCode&Python] Problem 700. Search in a Binary Search Tree
Given the root node of a binary search tree (BST) and a value. You need to find the node in the BST ...
- BZOJ1071: [SCOI2007]组队【双指针】【思维好题】
Description NBA每年都有球员选秀环节.通常用速度和身高两项数据来衡量一个篮球运动员的基本素质.假如一支球队里速度最慢的球员速度为minV,身高最矮的球员高度为minH,那么这支球队的所有 ...
- python去掉字符串'\xa0'
AssertionError: '5\xa0e\xa0*\xa0*\xa0*\xa05' != '5e***5'mystr = '5\xa0e\xa0*\xa0*\xa0*\xa05'mystr = ...
- java语法基础练习
1.阅读示例: EnumTest.java,并运行.分析结果 代码: public class EnumTest { public static void main(String[] args) { ...