第27章 项目8:使用XML-RPC进行文件共享
1.问题
创建一个简单的P2P文件共享程序。
P2P文件共享程序是在不同计算机上的程序交换文件。P2P交互内,任何节点(peer)都可以是链接到其他节点。在这样一个由节点组成的虚拟网络中,是没有中央节点的,这样网络会更强壮。P2P系统构建会有很多问题,但是大多数P2P系统都有聪明的方法来组织自己的结构。
需求:
(1)节点介绍自己给其他节点
(2)向节点请求文件
(3)为避免循环以及长距离请求,需要提供请求历史记录
(4)程序必须有连接到节点并且将自己表示为可信任参与者的方法
(5)必须提供用户界面
2.准备工具
使用的主要模块是xmlrpclib,SimpleXMLPRCServer。共享界面可以使用标准库中的cmd模块,以获得一些非常有限的并行效果。此外还有threading模块,urlparse模块。输入以下命令检查模块:
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
import threading
import urlparse

3.初次实现
启动两个交互式的Python解释器,第一个解释器内顺序输入:
from SimpleXMLRPCServer import SimpleXMLRPCServer
s = SimpleXMLRPCServer(("",4242))
def twice(x):
return x*2
s.register_function(twice)
s.serve_forever()
此时解释器被"挂起",等待RPC请求。为了创建请求,第二个解释器内输入:
from xmlrpclib import ServerProxy
s = ServerProxy('http://localhost:4242')
s.twice(2)
第二个解释器输出:4
第一个解释器输出:
127.0.0.1 - - [19/Nov/2016 13:48:02] "POST /RPC2 HTTP/1.1" 200 -

程序需求最重要的两个方面包括:Node要维护什么信息,必须执行什么操作。
27-1 simple_node.py ——简单的Node实现
在F:\program\pybook\27目录下创建两个文件夹files1和files2,在files2文件中放入test.txt文件,内容为"This is a test."。



打开两个cmd窗口,进入F:\program\pybook\27目录。
在第一个终端内运行:python simple_node.py http://localhost:4242 files1 secret1
在第二个终端内运行:python simple_node.py http://localhost:4243 files2 secret2

打开交互式Python解释器,输入如下代码,运行第一个节点:
from xmlrpclib import *
mypeer = ServerProxy('http://localhost:4242')
code, data = mypeer.query('test.txt')
code
输出:2
代码2表示获取失败。

运行第二个节点,代码如下:
otherpeer = ServerProxy('http://localhost:4243')
code, data = otherpeer.query('test.txt')
code
输出:1

输入:data
输出:'This is a test.'

把第一个节点介绍给第二个节点:mypeer.hello('http://localhost:4243')
输出:1

然后获取,就可以从第二个节点上得到test.txt文件:mypeer.query('test.txt')
输出:[1, 'This is a test.']

把第二个节点的文件下载到第一个节点上:mypeer.fetch('test.txt','secret1')
输出:1

返回值1表示成功了,在files1文件夹中查看,存在test.txt文件。


完整代码如下:
>>> from xmlrpclib import *
>>> mypeer = ServerProxy('http://localhost:4242')
>>> code, data = mypeer.query('test.txt')
>>> code
2
>>> otherpeer = ServerProxy('http://localhost:4243')
>>> code, data = otherpeer.query('test.txt')
>>> code
1
>>> data
'This is a test.'
>>> mypeer.hello('http://localhost:4243')
1
>>> mypeer.query('test.txt')
[1, 'This is a test.']
>>> mypeer.fetch('test.txt','secret1')
1
4.再次实现——该部分未能实现
27-2 server.py ——新的Node实现
# 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 #Seconds
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):
"""
Node类的简单的基于文本的界面。
"""
prompt = '> '
def __init__(self, url, dirname, urlfile):
"""
设定url、dirname和urlfile,并且在单独的线程中启动No的服务器。
"""
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):
'调用服务器的fetch方法'
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 #EOF与'exit'同义
def main():
url, directory, urlfile = sys.argv[1:]
print url, directory, urlfile
client = Client(url, directory, urlfile)
client.cmdloop()
if __name__ == '__main__': main()
27-3 client.py ——新的Node控制器界面
# 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 #Seconds
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):
"""
Node类的简单的基于文本的界面。
"""
prompt = '> '
def __init__(self, url, dirname, urlfile):
"""
设定url、dirname和urlfile,并且在单独的线程中启动No的服务器。
"""
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):
'调用服务器的fetch方法'
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 #EOF与'exit'同义
def main():
url, directory, urlfile = sys.argv[1:]
print url, directory, urlfile
client = Client(url, directory, urlfile)
client.cmdloop()
if __name__ == '__main__': main()
在F:\program\pybook\27目录下建立两个文件夹,files1和files2,并在文件夹中分别建立urls1.txt和urls2.txt文件,files2文件夹里面创建一个文件,dict.txt。在urls1.txt中写入:http://localhost:4243,然后开启两个cmd命令行,
url, directory, urlfile
第一个输入:python client.py urls1.txt files1 http://localhost:4242 并回车
但是,很遗憾尝试多次依然报错,尚未解决。
第27章 项目8:使用XML-RPC进行文件共享的更多相关文章
- 【ASP.NET MVC 5】第27章 Web API与单页应用程序
注:<精通ASP.NET MVC 3框架>受到了出版社和广大读者的充分肯定,这让本人深感欣慰.目前该书的第4版不日即将出版,现在又已开始第5版的翻译,这里先贴出该书的最后一章译稿,仅供大家 ...
- 什么是XML RPC?
# -*- coding: cp936 -*- #python 27 #xiaodeng #什么是XML RPC? #中文叫:远程过程调用 #使用http协议做传输协议的rpc机制,使用xml文本的方 ...
- 【STM32H7教程】第27章 STM32H7的TCM,SRAM等五块内存的动态内存分配实现
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第27章 STM32H7的TCM,SRAM等五块内 ...
- SpringMVC项目学习1_web.xml
最近接触的所有项目都是SpringMVC+ajax的项目,因此以一个项目为例学习下. --------------------------------------------------------- ...
- Gradle 1.12用户指南翻译——第四十一章. 项目报告插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- 【RL-TCPnet网络教程】第27章 DNS域名系统基础知识
第27章 DNS域名系统基础知识 本章节为大家讲解DNS(Domain Name System,域名系统),通过前面章节对TCP和UDP的学习,需要大家对DNS也有个基础的认识. (本章的知 ...
- JavaWeb项目中web.xml有关servlet的基本配置
JavaWeb项目中web.xml有关servlet的基本配置: 我们注意到,tomcat下的conf中也有一个web.xml文件,没错的,所有的JavaWeb项目中web.xml都继承自服务器下的w ...
- [Real World Haskell翻译]第27章 网络通信和系统日志 Sockets and Syslog
第27章 网络通信和系统日志 Sockets and Syslog 基础网络 在本书的前面几章,我们讨论了运转在网络上的服务.其中的两个例子是客户端/服务器架构的数据库和Web服务.当需要制定一个新的 ...
- The type javax.xml.rpc.ServiceException cannot be resolved.It is indirectly
The type javax.xml.rpc.ServiceException cannot be resolved.It is indirectly 博客分类: 解决方案_Java 问题描述:T ...
随机推荐
- input的button和submit的区别
故事由来: 其实这个问题,昨天已经遇到过,但是昨天是公司的一枚老员工帮助我这个实习生调的,而且我也确(猜)定(测)那枚老员工也不知道这个区别.然后今天又遇到相同问题. 故事梗概: 现在公司里面做一个项 ...
- Java学习笔记——字符串常用函数
class JavaTest4_String { public static void main(String[] args) { String str1 = "IOS,ANDROID,BB ...
- POJ 1679 The Unique MST (最小生成树)
The Unique MST Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22668 Accepted: 8038 D ...
- CENTOS如何禁用ROOT本地或远程SSH登录
下面详细描述如何禁止root登录. 禁止root本地登录 禁止root远程ssh登录 禁止root本地登录 修改/etc/pam.d/login文件增加下面一行 1 auth required p ...
- Ajax+JSON学习笔记(二)
来源:http://www.imooc.com/learn/250 readyState属性 0:请求未初始化,open还没有调用 1:服务器连接已建立,open已经调用了 2:请求已接受,也就是接收 ...
- Backbone.js学习之Model
首先,我们看一下官方文档中对Model的解释(或者说定义): Models are the heart of any JavaScript application, containing the in ...
- SQLServer Ansi_Padding的用法
关于Ansi_Padding的用法 1.当设置为ON时,不剪裁字符值中插入到varchar列的尾随空格和二进制值中插入到varbinary列的尾随零.不将值按列的长度进行填充. 2.当设置为OFF时, ...
- jquery与checkbox的checked属性的问题
1.页面加载成功后,点击选中或取消选中该checkbox,checkbox属性里的checked属性不会根据该checkbox是否选中而变化 2.checkbox里的onchange或onclick方 ...
- 利用kvc对UITabBar上的UITabBarButton的尝试修改.md
一.前言 一次比较懒的想法,不想自定义UITabBar,也不想用第三方框架,于是想尝试修改苹果私有类来达到部分效果 效果如下 点击tabBar 上的按钮,图片有变大再变小的动画 tabBar 上某个按 ...
- 遇见NodeJS:JavaScript的贵人
在大家的印象中,相当长一段时间里,JavaScript是一门脚本语言,一般不能成为某个项目的担纲主角,作用只是在浏览器里帮忙校验校验输入是不是正确,响应一下鼠标.键盘事件,或者让某个HTML元素动起来 ...