TinyP2P
Ed Felten撰写, Alex Halderman提供帮助。
TinyP2P是一个仅用15行Python代码来完成的,P2P方式共享文件的程序。我写这个程序主要想说明P2P程序其实并不难写。P2P程序可以非常的简单,任何有点技巧的程序员都可以写出来,因此禁止他们的创新是不可能的(译者注:可能是针对目前的一个P2P的诉讼而描述的吧)。
(每行代码少于80个字符。第一行作为说明并没有被电脑计算入内。)
我创建这个程序的目的不是想去帮助违反版权法的人。我不会宽恕违反版权法的事情。该程序的最优化设计被用来共享文件之外没有别的事情。程序对于(P2P)概念的接受还是很有帮助的。一个更实用的程序可以更快的运行,更加可靠和更好的错误处理机制。但是那样的话,需要更多的代码。
TinyP2P的代码可以在http://www.freedom-to-tinker.com/tinyp2p.py下载。
工作方式
程序创建了一个小世界网络,它可以被用来在朋友或者是商业上的文件共享。程序在非常大的网络下运行不是很好;不过可以用许多小网络来替代。每个网络都是密码保护的;一个网络尽被知道密码的人才可以访问。(但是网络对于那些会监控流量的攻击者来说并不是安全的。)
该程序使用标准的通信协议:HTTP和XML-RPC。HTTP就是通常被用来web浏览获取页面的那个协议,XML-RPC广泛的应用于web服务的提供。
本程序可以运行在服务器端或者是客户端中的一种模式下。当作为服务器运行时,程序可以连接到网络中的别的服务器,并且让当前目录下的所有文件被网络用户下载。(文件存放的目录就是用户联入之后可以立即访问的那个目录)运行该程序作为一个服务端,你只要使用如下命令:
python tinyp2p.py password server hostname portnum [otherurl]
命令行中的password就是访问网络需要的密码,hostname 和 portnum被用来构造服务器的URL(http://hostname:portnum),otherurl(附加的那个)是其它的已经作为网络的一部分运行的服务器的URL。(Otherurl可以被用来使你的服务器挂到网络上。如果你不提供otherurl,程序会认为你的服务器启动了一个新的网络。)
将程序运行为一个客户端,你可以使用下面的命令:
python tinyp2p.py password client serverurl pattern
命令里面的password是访问网络的密码,serverurl是网络内服务器的URL,pattern是一个字符串。该命令看起来好像是每个文件都被网络内的服务器所共享。一个文件被下载后,存放到当前目录中,2个条件:(a)文件名包含子串pattern,(b)当前目录下不存在同名文件。(注意:pattern可以是Python的正则表达式,只要能够被Python的re.search库调用来匹配文件名即可。)
注意,如果你在运行服务器端的目录下运行客户端时,客户端下载下来的软件自动的会被服务器端分发。这个要根据情况,不一定是你所想象的。还要注意的是,你可以在一个目录下运行多个服务器来加入不同的网络。
-----------------------------------------Code-----------------------------------------
# tinyp2p.py 1.0 (documentation at http://freedom-to-tinker.com/tinyp2p.html)
import sys, os, SimpleXMLRPCServer, xmlrpclib, re, hmac # (C) 2004, E.W. Felten
ar,pw,res = (sys.argv,lambda u:hmac.new(sys.argv[1],u).hexdigest(),re.search)
pxy,xs = (xmlrpclib.ServerProxy,SimpleXMLRPCServer.SimpleXMLRPCServer)
def ls(p=""):return filter(lambda n:(p=="")or res(p,n),os.listdir(os.getcwd()))
if ar[2]!="client": # license: http://creativecommons.org/licenses/by-nc-sa/2.0
??? myU,prs,srv = ("http://"+ar[3]+":"+ar[4], ar[5:],lambda x:x.serve_forever())
??? def pr(x=[]): return ([(y in prs) or prs.append(y) for y in x] or 1) and prs
??? def c(n): return ((lambda f: (f.read(), f.close()))(file(n)))[0]
??? f=lambda p,n,a:(p==pw(myU))and(((n==0)and pr(a))or((n==1)and [ls(a)])or c(a))
??? def aug(u): return ((u==myU) and pr()) or pr(pxy(u).f(pw(u),0,pr([myU])))
??? pr() and [aug(s) for s in aug(pr()[0])]
??? (lambda sv:sv.register_function(f,"f") or srv(sv))(xs((ar[3],int(ar[4]))))
for url in pxy(ar[3]).f(pw(ar[3]),0,[]):
??? for fn in filter(lambda n:not n in ls(), (pxy(url).f(pw(url),1,ar[4]))[0]):
??????? (lambda fi:fi.write(pxy(url).f(pw(url),2,fn)) or fi.close())(file(fn,"wc"))