Python项目9:文件共享2

本项目基于Python基础教程,修改后的代码适用于Win7及Python3.4.3,使用内置的Tkinter库创建简单界面。通过SimpleXMLRPCServer和ServerProxy实现文件共享。客户端在files2目录中添加testfile.txt进行下载测试。
摘要由CSDN通过智能技术生成

代码地址:https://code.csdn.net/ranky2009/pythonsmallproject

本项目基于Python基础教程(第二版)中的项目9:文件共享2。对代码略做修改,使得代码能在Win7系统,python3.4.3版本上运行。

原文中使用的是wxpython工具包做的界面,本处采用python中自带的tkinter制作简单的界面

代码如下:

1.    simple_gui_client.py

import tkinter as tk
from client import Client
import sys

class Application(tk.Frame):
    def __init__(self, master=None, client=None):
        tk.Frame.__init__(self, master)
        self.text = 'File Sharing Client'
        self.pack()
        self.createWidgets()
        self.client = client

    def createWidgets(self):
        self.httpurlEntry = tk.Entry(self)
        self.httpurlEntry.pack()
        
        self.hi_there = tk.Button(self)
        self.hi_there["text"] = "Fetch"
        self.hi_there["command"] = self.say_hi
        self.hi_there.pack()
        #self.hi_there.pack(side="top")

        self.QUIT = tk.Button(self, text="QUIT", fg="red",
                                            command=self.master.destroy)
        self.QUIT.pack(side="bottom")

    def say_hi(self):
        text = self.httpurlEntry.get()
        print(text)
        self.client.do_fetch(text)

def main():
    urlfile, directory, url = sys.argv[1:]
    if urlfile and directory and url:
        client = Client(url, directory, urlfile)
    root = tk.Tk()
    app = Application(master=root, client=client)
    app.mainloop()

if __name__ == '__main__': main()

2.    client.py

from os import path
from random import choice
from string import ascii_lowercase
from server import Node, UNHANDLED
from threading import Thread
from time import sleep
from xmlrpc.client import ServerProxy, Fault
import sys

HEAD_START = 0.1 # Seconds
SECRET_LENGTH = 100

def randomString(length):
    chars = []
    letters = ascii_lowercase[:26]
    while length > 0:
        length -= 1
        chars.append(choice(letters))
    return ''.join(chars)
    
class Client():
    def __init__(self, url, dirname, urlfile):
        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)
        urlfile = path.join(dirname, urlfile)
        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 as f:
            if f.faultCode != UNHANDLED: raise
            print("Couldn't find the file", arg)
    
def main():
    urlfile, directory, url = sys.argv[1:]
    client = Client(url, directory, urlfile)

if __name__ == '__main__': main()
3.    server.py

from os.path import join, isfile, abspath
from xmlrpc.client import Fault
from xmlrpc.server import SimpleXMLRPCServer
from xmlrpc.client import ServerProxy
from urllib.parse import urlparse
import sys

MAX_HISTORY_LENGTH = 6

UNHANDLED     = 100
ACCESS_DENIED = 200

class UnhandleQuery(Fault):
    def __init__(self, message="Couldn't handle the query"):
        Fault.__init__(self, UNHANDLED, message)
        
class AccessDenied(Fault):
    def __init__(self, message="Acces denied"):
        Fault.__init__(self, ACCESS_DENIED, message)
        
def inside(dir, name):
    dir = abspath(dir)
    name = abspath(name)
    return name.startswith(join(dir, ''))
    
def getPort(url):
    '在URL中提取端口'
    name = urlparse(url)[1]
    parts = name.split(':')
    return int(parts[-1])
    
class Node:
    """
    P2P网络中的节点。
    """
    def __init__(self, url, dirname, secret):
        self.url = url
        self.dirname = dirname
        self.secret = secret
        self.known = set()
        
    def query(self, query, history=[]):
        """
        查询文件,可能会向其他已知节点请求帮助。讲文件作为字符串返回。
        """
        print('in function query')
        try:
            content = self._handle(query)
        except:
            history = history + [self.url]
            print('in funciton query, history : %s' % history)
            if len(history) >= MAX_HISTORY_LENGTH: raise
            content = self._broadcast(query, history)
        return content
            
    def hello(self, other):
        """
        用于将节点介绍给其他节点。
        """
        self.known.add(other)
        return 0
        
    def fetch(self, query, secret):
        """
        用于让节点找到文件并且下载。
        """
        #print(query)
        #print(secret)
        if secret != self.secret: raise AccessDenied
        result = self.query(query)
        #print(result)
        f = open(join(self.dirname, query), 'w')
        f.write(result)
        f.close()
        return 0
                
    def _start(self):
        """
        内部使用,用于启动XML_RPC服务器。
        """
        s = SimpleXMLRPCServer(("", getPort(self.url)))
        s.register_instance(self)
        s.serve_forever()
        
    def _handle(self, query):
        """
        内部使用,用于处理请求。
        """
        dir = self.dirname
        name = join(dir, query)
        print('in function _handle, file name : %s' % name)
        if not isfile(name): raise UnhandleQuery
        if not inside(dir, name): raise AccessDenied
        return open(name).read()
        
    def _broadcast(self, query, history):
        for other in self.known.copy():
            print('other: %s' % other)
            if other in history: continue
            try:
                s = ServerProxy(other)
                return s.query(query, history)
            except Fault as f:
                if f.faultCode == UNHANDLED: pass
                else: self.known.remove(other)
            except:
                self.known.remove(other)
        raise UnhandleQuery
        
def main():
    url, directory, secret = sys.argv[1:]
    n = Node(url, directory, secret)
    n._start()
    
if __name__ == '__main__': main()
启动程序:

前期准备与project8类似。创建两个文件夹files1,files2,在这个两个文件夹中创建配置urlfile.txt,

files1中urlfile.txt的内容为http://localhost:4243,files2中的配置文件内容为空。

在files2文件夹中添加一个文件testfile.txt,用来下载。

启动一个server.
在cmd中输入python server.py files2 12345
启动另外一个cmd,输入python simple_gui_client.py urlfile.txt files1 http://localhost:4242
在启动的界面中的文本框中输入testfile.txt,然后点击fetch按钮,就可以发现文件已经下载到文件夹files1中了了


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值