2008年04月13日

TinyP2P使用15行代码实现了一个P2P的工具,下面是经过别人注释的代码:

:
  1. # tinyp2p.py 1.0 (documentation at http://freedom-to-tinker.com/tinyp2p.html)
  2. # (C) 2004, E.W. Felten
  3. # license: http://creativecommons.org/licenses/by-nc-sa/2.0
  4.  
  5.  
  6. # Annotated by Kochin Chang, Jan. 2005
  7.  
  8.  
  9. # Usage:
  10. #   Server - tinyp2p.py password server hostname  portnum [otherurl]
  11. #   Client - tinyp2p.py password client serverurl pattern
  12. #                   ar[0]      ar[1]    ar[2]  ar[3]     ar[4]   ar[5]
  13.  
  14.  
  15. import sys, os, SimpleXMLRPCServer, xmlrpclib, re, hmac
  16. # Import libraries used in the program.
  17. # sys : system variables and functions.
  18. # os : portable OS dependent functionalities.
  19. # SimpleXMLRPCServer : basic XML-RPC server framework.
  20. # xmlrpclib : XML-RPC client support.
  21. # re : regular expression support.
  22. # hmac : RFC 2104 Keyed-Hashing Message Authentication.
  23.  
  24.  
  25. ar,pw,res = (sys.argv,lambda u:hmac.new(sys.argv[1],u).hexdigest(),re.search)
  26. # A multiple assignment.
  27. # ar <- sys.argv : the argument list.
  28. # pw <- lambda u:hmac.new(sys.argv[1],u).hexdigest() :
  29. #   a function makes an HMAC digest from a URL.
  30. #   INPUT: a string, u, which is a URL here.
  31. #   OUTPUT: a hexdecimal HMAC digest.
  32. #   DESCRIPTION:
  33. #     1. Creates a HMAC object from the URL using network's password,
  34. #        sys.argv[1], as the key.
  35. #     2. Returns a hexdecimal digest of the HMAC object.
  36. # res <- re.search : alias for the regular expression search function.
  37.  
  38. pxy,xs = (xmlrpclib.ServerProxy,SimpleXMLRPCServer.SimpleXMLRPCServer)
  39. # A multiple assignment.
  40. # pxy <- xmlrpclib.ServerProxy : alias for the ServerProxy class.
  41. # xs <- SimpleXMLRPCServer.SimpleXMLRPCServer : alias for the SimpleXMLRPCServer class.
  42.  
  43. def ls(p=""):return filter(lambda n:(p=="")or res(p,n),os.listdir(os.getcwd()))
  44. # a function lists directory entries.
  45. # INPUT: a string, p, which is a regular expression pattern.
  46. # OUTPUT: a list of directory entries matched the pattern.
  47. # DESCRIPTION:
  48. #   1. Creates a function using lambda expression that takes a pathname as its
  49. #      parameter. The function returns true if the pattern is empty or the
  50. #      pathname matches the pattern.
  51. #   2. Finds out what is the current working directory.
  52. #   3. Retrieves a list of directory entries of current working directory.
  53. #   4. Filters the list using the lambda function defined.
  54.  
  55. if ar[2]!="client":
  56. # Running in server mode...
  57.  
  58.   myU,prs,srv = ("http://"+ar[3]+":"+ar[4], ar[5:],lambda x:x.serve_forever())
  59.   # A multiple assignment.
  60.   # myU <- "http://"+ar[3]+":"+ar[4] : server's own URL.
  61.   # prs <- ar[5:] : URL's of other servers in the network.
  62.   # srv <- lambda x:x.serve_forever() :
  63.   #   a function to start a SimpleXMLRPCServer.
  64.   #   INPUT: a SimpleXMLRPCServer object, x.
  65.   #   OUTPUT: (none)
  66.   #   DESCRIPTION:
  67.   #     Calls the server's serve_forever() method to start handling request.
  68.  
  69.   def pr(x=[]): return ([(y in prs) or prs.append(y) for y in x] or 1) and prs
  70.   # a function returns the server list.
  71.   # INPUT: a list, x, of servers' URLs to be added to the server list.
  72.   # OUTPUT: the updated server list.
  73.   # DESCRIPTION:
  74.   #   1. For each URL in x, checks whether it's already in the server list.
  75.   #      If it's not in the list, appends in onto the list.
  76.   #   2. Returns the updated server list.
  77.  
  78.   def c(n): return ((lambda f: (f.read(), f.close()))(file(n)))[0]
  79.   # a function returns content of the specified file.
  80.   # INPUT: a string, n, which is a filename.
  81.   # OUTPUT: the content of the file in a string.
  82.   # DESCRIPTION:
  83.   #   1. Creates a function using lambda expression that takes a file object, f,
  84.   #      as its parameter. The function reads the content of the file, then
  85.   #      closes it. The results of the read and close are put into a tuple, and
  86.   #      the tuple is returned.
  87.   #   2. Creates a file object with the filename. Passes it to the lambda
  88.   #      function.
  89.   #   3. Retrieves and returns the first item returned from the lambda function.
  90.  
  91.   f=lambda p,n,a:(p==pw(myU))and(((n==0)and pr(a))or((n==1)and [ls(a)])or c(a))
  92.   #   a request handling function, depending on the mode, returns server list,
  93.   #   directory entries, or content of a file.
  94.   #   INPUT: a string, p, which is a hexdecimal HMAC digest.
  95.   #          a mode number, n.
  96.   #          if n is 0, a is a list of servers to be added to server list.
  97.   #          if n is 1, a is a pattern string.
  98.   #          if n is anything else, a is a filename.
  99.   #   OUTPUT: if n is 0, returns the server list.
  100.   #           if n is 1, returns directory entries match the pattern.
  101.   #           if n is anything else, returns content of the file.
  102.   #   DESCRIPTION:
  103.   #     1. Verifies the password by comparing the HMAC digest received and the
  104.   #        one created itself. Continues only when they match.
  105.   #     2. If n is 0, calls pr() to add list, a, and returns the result.
  106.   #        If n is 1, calls ls() to list entries match pattern a, and returns
  107.   #        the result enclosed in a list.
  108.   #        If n is any other value, retreives and return content of the file
  109.   #        with filename specified in a.
  110.  
  111.   def aug(u): return ((u==myU) and pr()) or pr(pxy(u).f(pw(u),0,pr([myU])))
  112.   # a function augments the network.
  113.   # INPUT: a string, u, which is a URL.
  114.   # OUTPUT: a list of URL's of servers in the network.
  115.   # DESCRIPTION:
  116.   #   1. If the URL, u, equals to my own URL, just returns the server list.
  117.   #   2. Otherwise, creates a ServerProxy object for server u. Then calls its
  118.   #      request handling function f with a HMAC digest, mode 0, and server
  119.   #      list with myself added.
  120.   #   3. Calls pr() with the result returned from server u to add them to my
  121.   #      own list.
  122.   #   4. Returns the new list.
  123.  
  124.   pr() and [aug(s) for s in aug(pr()[0])]
  125.   # 1. Checks the server list is not empty.
  126.   # 2. Takes the first server on the list. Asks that server to augment its
  127.   #    server list with my URL.
  128.   # 3. For each server on the returned list, asks it to add this server to its
  129.   #    list.
  130.  
  131.   (lambda sv:sv.register_function(f,"f") or srv(sv))(xs((ar[3],int(ar[4]))))
  132.   # Starts request processing.
  133.   # 1. Defines a function with lambda expression that takes a SimpleXMLRPCServer
  134.   #    object, registers request handling function, f, and starts the server.
  135.   # 2. Creates a SimpleXMLRPCServer object using hostname (ar[3]) and portnum
  136.   #    (ar[4]). Then feeds the object to the lambda function.
  137.  
  138. # Running in client mode...
  139. for url in pxy(ar[3]).f(pw(ar[3]),0,[]):
  140. # 1. Create a ServerProxy object using the serverurl (ar[3]).
  141. # 2. Calls the remote server and retrieves a server list.
  142. # 3. For each URL on the list, do the following:
  143.  
  144.   for fn in filter(lambda n:not n in ls(), (pxy(url).f(pw(url),1,ar[4]))[0]):
  145.   # 1. Create a ServerProxy object using the URL.
  146.   # 2. Calls the remote server to return a list of filenames matching the
  147.   #    pattern (ar[4]).
  148.   # 3. For each filename doesn't exist locally, do the following:
  149.  
  150.     (lambda fi:fi.write(pxy(url).f(pw(url),2,fn)) or fi.close())(file(fn,"wc"))
  151.     # 1. Define a lambda function that takes a file object, calls remote server
  152.     #    for the file content, then closes the file.
  153.     # 2. Create a file object in write and binary mode with the filename. (I
  154.     #    think the mode "wc" should be "wb".)
  155.     # 3. Passes the file object to the lambda function.

如果直接运行上面的代码会有问题(不知道作者那里为什么会正常运行),会有类似这样的错误提示:

:
  1. Traceback (most recent call last):
  2. File "tinyp2p.py", line 14, in ?
  3. for url in pxy(ar[3]).f(pw(ar[3]),0,[]):
  4. File "/usr/lib/python2.4/xmlrpclib.py", line 1096, in __call__
  5. return self.__send(self.__name, args)
  6. File "/usr/lib/python2.4/xmlrpclib.py", line 1383, in __request
  7. verbose=self.__verbose
  8. File "/usr/lib/python2.4/xmlrpclib.py", line 1147, in request
  9. return self._parse_response(h.getfile(), sock)
  10. File "/usr/lib/python2.4/xmlrpclib.py", line 1286, in _parse_response
  11. return u.close()
  12. File "/usr/lib/python2.4/xmlrpclib.py", line 744, in close
  13. raise Fault(**self._stack[0])
  14. xmlrpclib.Fault: <Fault 1: 'exceptions.TypeError:coercing to Unicode:
  15. need string or buffer, list found'>

经google的帮助在这里找到的解决方案:

:
  1. pr() and [aug(s) for s in aug(pr()[0])]
  2. to
  3. pr() and [aug(s) for s in aug(pr()[0])] or pr([myU])

代码中大量应用了lambda,还有and,or,虽然这种代码风格不值得我们学习,我们可以写出更清昕的代码,但作者是为了证明P2P应用程序是如何容易实现,作者更希望可以把代码写的更简洁,可以用在他的签名里。

还有perl写的6行代码,我看了一下grep,cat这些都出来了,是shell版吧。

标签 :

5 楼了已经

  • luguo写于08年04月13日

    lambda,map,reduce啊,都是很nb的!
    弱弱地问一下:p2p和xmlrpc有啥关系??

  • cocobear写于08年04月13日

    XMLRPC可以实现分布式处理,这样P2P可以使用多个Server,俺这样觉得 。

  • luguo写于08年04月14日

    那6行Perl在哪里??
    Perl自己有内置的grep,也很nb。虽然没cat,但可以定义个子函数叫cat。

  • luguo写于08年04月14日

    还有,你最后那段Python不对啊!人家是说把上面那行换成下面那行,那个“to”明显不是Python源代码啊!

  • cocobear写于08年04月15日

    http://ansuz.sooke.bc.ca/software/molester/molester-min

    这里有一个,貌似我上次看到的不是这个。

    最后那一段只是个说明,并不是python源代码。

发表评论

在下面加入你的评论,或者 trackback 从你的博客站点。 订阅本文的评论。

:

:

:

« 又开始肚疼了
» 换了个域名cocobear.info