FTP做業

模擬實現一個FTP

[博客地址](http://www.cnblogs.com/mologa-jie/p/8378070.html)

1.做業需求

```
角色:ftp_s(server)、ftp_c(client)、{事例用戶:miao=passwd=>miao,abu=passwd=>abu}
要求:
開發簡單的FTP:
1. 用戶登錄
2. 上傳/下載文件
3. 不一樣用戶家目錄不一樣
4. 查看當前目錄下文件
5. 充分使用面向對象知識
```

2.需求分析



1) 用戶登陸

client
'''用戶加密認證'''
class log_in(object):

    _flag=False
    _times = 1
    def __init__(self):
        pass

    def auth(self,user):
        while not self._flag:
            # value = getpass.getpass("\033[35;1m請輸入用戶密碼:\033[0m") #terminal 模式下支持運行,否則會直接卡主
            value = input("\033[35;1m請輸入用戶密碼:\033[0m").strip()
            md5_value = hashlib.md5(value.encode('utf-8')).hexdigest()
            new_member = (user,md5_value)
            new_member = str(new_member)
            new_member = "auth_" + new_member
            res = client_sock.auth_transform(new_member)
            if res is True:
                print("welcome to my ftp.py server!")
                self._flag =  True
                return self._flag
            elif self._times < 3:
                self._times += 1
                print("\033[31;1m密碼錯誤,從新輸入!\033[0m")
                continue
            else:
                print("\033[31;1m密碼錯誤屢次,請聯繫管理員。\033[0m")
                return self._flag

    def register(self,user):
        while not self._flag:
            # value = getpass.getpass("\033[35;1m請輸入用戶密碼:\033[0m")
            value = input("\033[35;1m請輸入用戶密碼:\033[0m").strip()
            # re_value = getpass.getpass("\033[35;1m請再次輸入用戶密碼:\033[0m")
            re_value = input("\033[35;1m請再次輸入用戶密碼:\033[0m").strip()
            if value == re_value:
                print("\033[34;1m註冊中……!\033[0m")
                md5_value = hashlib.md5(value.encode('utf-8')).hexdigest()
                new_member = (user,md5_value)
                new_member = str(new_member)
                new_member = "register_"+new_member
                res = client_sock.auth_transform(new_member)
                if self._flag != res:
                    return res
                else:
                    print("註冊失敗!")
                    continue
            elif self._times < 3:
                self._times += 1
                print("\033[31;1m密碼不一致,從新輸入!\033[0m")
                continue
            else:
                print("\033[31;1m密碼錯誤屢次,請聯繫管理員。\033[0m")
                return self._flag

  

server
'''用戶加密認證'''
class log_in(object):

    member_list=auth.auth_file().read_file()

    def auth(self,args):
        args = eval(args)
        if args in self.member_list.items():
            return True
        else:
            return False

    def register(self,args):
        self.member_list.update(args)
        auth.auth_file().write_file(self.member_list)
        return True

  



`client`展現:
------- 歡迎進入FTP ---------

1. 註冊
2. 登陸
3. 退出

請選擇:2
請輸入用戶名:abu
請輸入用戶密碼:abu
welcome to my ftp.py server!

------- abu我的空間 ---------

1. 傳輸文件
2. 命令交互
3. 退出

請選擇:2

------- 命令行模式 ---------

1. 當前用戶根目錄
2. 支持經常使用命令{eq: ls }
3. 退出 quit

Sent: dir
Received: 驅動器 F 中的卷是 生活
卷的序列號是 1C94-79CB

F:\mologa-workspace\week_5\week-5\ftp_s\user_root\abu 的目錄

2018/01/29 14:21 <DIR> .
2018/01/29 14:21 <DIR> ..
2018/01/29 14:21 4,672,137 bible.txt
1 個文件 4,672,137 字節
2 個目錄 298,844,962,816 可用字節

Sent: quit
=-=-=-=-=-=-=-=-=-=-=-=-=-=退出模塊=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

------- abu我的空間 ---------

1. 傳輸文件
2. 命令交互
3. 退出

請選擇:3
終止

`server`log展現:

127.0.0.1 request
Mon Jan 29 15:50:08 2018 : abu 認證成功
127.0.0.1 request
Mon Jan 29 15:50:13 2018 : abu 執行 dir
127.0.0.1 request
Mon Jan 29 15:50:17 2018 : abu 用戶退出!


2)上傳、下載


client
def recvfile(user,client_command):
    HOST, PORT = "localhost", 8888
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((HOST, PORT))
    action,filename = client_command.split()
    file_path = os.path.join(((sys.path)[-1]), "user_home")
    f_path = os.path.join(file_path, user)
    filename = os.path.join(f_path, filename)
    if os.path.isfile(filename):
        print("文件已經存在!")
        return "fail"
    msg = "file_('%s','%s')"%(user,client_command)
    client.send(msg.encode())
    data = str(client.recv(1024),'utf-8')
    if data == 'ready':
        f = open(filename, 'wb')
        while True:
            data = client.recv(102400)
            if data == b'EOF':
                print("recv file success!")
                break
            f.write(data)
        f.close()
        return "success"
    else:
        print("文件下行錯誤!")
        return "fail"

def sendfile(user,client_command):
    HOST, PORT = "localhost", 8888
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect((HOST, PORT))
    action, filename = client_command.split()
    file_path = os.path.join(((sys.path)[-1]), "user_home")
    f_path = os.path.join(file_path, user)
    filename = os.path.join(f_path, filename)
    if os.path.isfile(filename):
        msg = "file_('%s','%s')"%(user,client_command)
        client.send(msg.encode())
        flag = client.recv(1024)
        if flag == b'ready':
            f = open(filename, 'rb')
            while True:
                data = f.read(102400)
                if not data:
                    break
                client.sendall(data)
            f.close()
            time.sleep(1)
            client.sendall('EOF'.encode())
            print("傳輸成功!")
            return "success"
        else:
            print("操做失敗!")
            return "fail"
    else:
        print("文件不存在!")
        return "fail"

  


server
filename_c = (eval(args))[1]
filec,filename = filename_c.split(' ')
if filec == 'put':
    file_path = os.path.join(((sys.path)[-1]), "user_root")
    f_path = os.path.join(file_path, user)
    filename = os.path.join(f_path, filename)
    if os.path.isfile(filename) is False:
        syn = "ready"
        self.request.sendall(syn.encode())
        f = open(filename, 'wb')
        while True:
            data = self.request.recv(102400)
            if data == b'EOF':
                break
            if not data:
                break
            f.write(data)
        f.close()
        time.sleep(1)
        print(" {} : {} {} 傳輸成功".format(time.ctime(), user,filename_c))
    else:
        self.request.sendall("False".encode())
        print(" {} : {} {} 傳輸失敗".format(time.ctime(), user, filename_c))
elif filec == 'get':
    file_path = os.path.join(((sys.path)[-1]), "user_root")
    f_path = os.path.join(file_path, user)
    filename = os.path.join(f_path, filename)
    if os.path.isfile(filename) is True:
        syn = "ready"
        self.request.sendall(syn.encode())
        f = open(filename, 'rb')
        while True:
            data = f.read(102400)
            if not data:
                break
            self.request.sendall(data)
        f.close()
        time.sleep(1)
        self.request.sendall('EOF'.encode())
        print(" {} : {} {} 傳輸成功".format(time.ctime(), user, filename_c))
    else:
        self.request.sendall("False".encode())
        print(" {} : {} {} 傳輸失敗".format(time.ctime(), user, filename_c))
else:
    errmsg = ("格式錯誤!")
    self.request.sendall(errmsg.encode())
    print(" {} : {} {}".format(time.ctime(), user, errmsg))
    pass

  



`client`展現:

------- 文件操做 ---------

支持任何文件格式 gz zip mp4 txt
1. 上傳文件 {eq: put filename}
2. 下載文件 {eq: get filename}
3. 退出 {eq: quit}
4. 暫時不支持覆蓋文件

abu #get bible.txt
recv file success!
abu #quit
=-=-=-=-=-=-=-=-=-=-=-=-=-=退出模塊=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

------- abu我的空間 ---------

1. 傳輸文件
2. 命令交互
3. 退出

請選擇:2

------- 命令行模式 ---------

1. 當前用戶根目錄
2. 支持經常使用命令{eq: ls }
3. 退出 quit

Sent: dir
Received: 驅動器 F 中的卷是 生活
卷的序列號是 1C94-79CB

F:\mologa-workspace\week_5\week-5\ftp_s\user_root\abu 的目錄

2018/01/29 14:21 <DIR> .
2018/01/29 14:21 <DIR> ..
2018/01/29 14:21 4,672,137 bible.txt
1 個文件 4,672,137 字節
2 個目錄 298,844,844,032 可用字節

Sent: quit
=-=-=-=-=-=-=-=-=-=-=-=-=-=退出模塊=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

`server`log展現:

127.0.0.1 request
Mon Jan 29 16:06:13 2018 : abu 認證成功
127.0.0.1 request
Mon Jan 29 16:06:24 2018 : abu get bible.txt 傳輸成功
127.0.0.1 request
Mon Jan 29 16:06:34 2018 : abu 執行 dir


3)編碼轉換

def run_command(self,com):
    root_path = (file_path + os.sep + self.user)
    res = subprocess.run("%s" % com, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE,cwd=root_path)
    if platform.system() == "Windows":
        code = 'gbk'
    else:
        code = 'utf-8'
    if res.returncode is 0:
        ack = (res.stdout).decode(code)
    else:
        ack = (res.stderr).decode(code)
    return ack

  




總結備註```堅持學習真的很重要;學習: 1.str,byte,gbk編碼的轉換和了解 2.學習了socket的端口工做原理 3.多樣化數據格式定義與統一化 file: file_(put file) file_(get file) command: com_(command) auth: auth_('user','password') |__login、register、auth register_{'abc': '900150983cd24fb0d6963f7d28e17f72'} client: new_member = (user,md5_value) new_member = str(new_member) new_member = "register_"+new_member 將字典轉換成元組,到server端以後統一切分以後再轉換回字典 server: key = eval(args)[0] value = eval(args)[1] args = {key:value} auth_('miao', '1058a42a81e5252c76cb308bcd6a0214') com_('miao', 'dir') file_('miao', 'bible.txt') 經過:mode, args = msg.split('_') 分別選擇模式-->執行args```
相關文章
相關標籤/搜索