FTP
Posted Remember
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FTP相关的知识,希望对你有一定的参考价值。
环境:windows Python 3.5
实现功能:
注册/登陆,不同用户家目录不同,查看登陆用户家目录下文件,上传到登陆用户家目录下,从登陆用户家目录下下载
结构:
FTP--|
clients--|
conf--|
config.py-- ……客户端参数,IP,PORT
core--|
client.py-- ……客户端启动文件
servers--|
conf--|
config.py-- ……服务端参数,IP,PORT,上传最大文件大小,家目录路径
core--|
client.py-- ……服务端启动文件
db --|
data.py-- ……存储,读取用户信息
home--| 存放不同用户家目录
如何使用:
启动服务端servers.core.servers.py文件
启动客户端clients.core.client.py文件(可多用户登陆)
未注册先注册,注册后登陆
根据需求选择相应操作:
上传默认路径为登陆用户家目录 home/name
下载默认从登陆用户家目录下下载文件,使用下载前先上传文件,否则将无任何文件可下载
客户端代码:
import os import configparser PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) class Configuration(object): def __init__(self): self.config = configparser.ConfigParser() self.name = PATH+os.sep+"conf"+os.sep+"system.ini" def init_config(self): # 初始化配置文件,ip :客户端IP,port:客户端端口 if not os.path.exists(self.name): self.config["config"] = {"ip":"localhost","port":6666} self.config.write(open(self.name, "w", encoding="utf-8", )) def get_config(self, head="config"): \'\'\' 获取配置文件数据 :param head: 配置文件的section,默认取初始化文件config的数据 :return:返回head中的所有数据(列表) \'\'\' self.init_config() # 取文件数据之前生成配置文件 self.config.read(self.name, encoding="utf-8") if self.config.has_section(head): section=self.config.sections() return self.config.items(section[0])
#!/usr/bin/env python # -*-coding:utf-8-*- # _author_=zh import os import sys import socket import hmac PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(PATH) from conf import config class Client(object): def __init__(self, ip, port): # 创建连接 self.ip = str(ip) self.port = int(port) self.client = socket.socket() self.client.connect((self.ip, self.port)) def send_pwd(self): # 注册和登录中公有的操作,返回服务器返回的标识,0为成功,1为失败,返回登录人名称 logo_name = input("name:") pwd = input("pwd:") data = "%s" % ([logo_name, self.encrypt("pwd", pwd)]) self.client.sendall(data.encode()) accept_data = self.client.recv(1024) return accept_data, logo_name def login(self): # 注册 self.client.sendall("login".encode()) while True: accept_data, logo_name = self.send_pwd() if accept_data.decode() == "0": return None elif accept_data.decode() == "1": print("账号已存在") break def logon(self): # 登录,登录成功返回登录人姓名 self.client.sendall("logon".encode()) count = 0 while True: accept_data, logo_name = self.send_pwd() if accept_data.decode() == "0": return logo_name elif accept_data.decode() == "1": print("账号或密码错误") count += 1 if count > 2: break def watch(self, logo_name): # 查看登陆用户家目录下文件 self.client.sendall("watch".encode()) data = ["dir", logo_name] self.client.sendall(str(data).encode()) accept_data = self.client.recv(1024) accept_data = accept_data.decode() print(accept_data) def upload(self, logo_name): # 上传,上传到home目录下 self.client.send("upload".encode()) path = input("请输入需要上传的文件路径:") length = os.path.getsize(path) file_name = path[path.rfind("\\\\")+1:] data = ("[\'%s\',\'%s\',\'%s\']" % (length, file_name, logo_name)).encode() self.client.send(data) sign = (self.client.recv(1024)).decode() if sign == "1": print("家目录空间不足") else: get_length = (self.client.recv(1024)).decode() if get_length == "None": print("文件已存在") else: get_length = int(get_length) conf = hmac.new("file".encode()) with open(path, "rb") as send_data: send_data.seek(get_length) send_data = send_data.read() conf.update(send_data) pwd = conf.hexdigest() self.client.sendall(send_data) if (self.client.recv(1024)).decode() == "0": self.client.send(pwd.encode()) if (self.client.recv(1024)).decode() == "0": print("上传成功") else: print("上传失败") def download(self, logo_name): # 下载,从登陆用户家目录下载到指定位置 self.client.send("download".encode()) self.client.send(("%s" % logo_name).encode()) show_data = self.client.recv(1024) print(show_data.decode()) while True: file_name = input("请输入需要下载的文件名:") if "." not in file_name: print("文件名需带格式后缀") address = input("请输入下载路径:") if os.path.exists(address): break print("文件路径不存在,重新输入") self.client.send(file_name.encode()) length_data = self.client.recv(1024) length_data = eval(length_data.decode()) if length_data == 1: print("文件不存在") else: length = length_data[0] pwd = length_data[1] self.client.send("0".encode()) all_data = b\'\' while True: if len(all_data) == int(length): break else: data = self.client.recv(1024) all_data += data ret = len(all_data) / int(length) num = int(ret * 100) view = \'\\r [%-100s]%d%%\' % ("=" * num, 100,) sys.stdout.write(view) sys.stdout.flush() path = address+os.sep+file_name if os.path.isfile(path): print("文件已存在") else: conf = hmac.new("file".encode()) with open(path, "wb") as file: file.write(all_data) conf.update(all_data) new_pwd = conf.hexdigest() if new_pwd == pwd: print("下载成功") else: print("下载失败") os.remove(path) def encrypt(self, keys, data): # hmac加密 conf = hmac.new(keys.encode()) conf.update(data.encode()) return conf.hexdigest() if __name__ == \'__main__\': while True: info = config.Configuration() info_list = info.get_config() obj_client = Client(info_list[0][1], info_list[1][1]) info = \'\'\'---welcome--- 1.登录 2.注册 \'\'\' print(info) num = input("-->") setattr(obj_client, "1", obj_client.logon) setattr(obj_client, "2", obj_client.login) if hasattr(obj_client, num): name = getattr(obj_client, num)() else: print("输入错误,请重新输入") continue if name: break else: print("请登录") while True: info = \'\'\' 1.查看家目录下文件 2.上传 3.下载 4.注销 \'\'\' print(info) num = input("-->") if num == "4": exit() setattr(obj_client, "1", obj_client.watch) setattr(obj_client, "2", obj_client.upload) setattr(obj_client, "3", obj_client.download) if hasattr(obj_client, num): getattr(obj_client, num)(name) else: print("输入错误,请重新输入") continue
服务端代码:
import os import configparser PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) class Configuration(object): def __init__(self): self.config = configparser.ConfigParser() self.name = PATH+os.sep+"conf"+os.sep+"system.ini" def init_config(self): # 初始化配置文件,IP:服务端IP,port:服务端端口,limit_size:家目录容量,HOME_PATH:用户家目录地址 if not os.path.exists(self.name): self.config["config"] = {"ip": "localhost", "port": 6666, "limit_size": 10240000, "HOME_PATH": PATH+os.sep+"home"+os.sep} self.config.write(open(self.name, "w", encoding="utf-8", )) def get_config(self, head="config"): \'\'\' 获取配置文件数据 :param head: 配置文件的section,默认取初始化文件config的数据 :return:返回head中的所有数据(列表) \'\'\' self.init_config() # 取文件数据之前生成配置文件 self.config.read(self.name, encoding="utf-8") if self.config.has_section(head): section = self.config.sections() return self.config.items(section[0])
import shelve import os PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+os.sep+"db"+os.sep def write(name, data): \'\'\' 存储个人信息 :param data: 存储的数据 :param name: shelve的key \'\'\' file = shelve.open("%sdata" % PATH) file[name] = data file.close() def read(name): \'\'\' 读取个人信息 :param name:存储时传入的name :return:返回个人信息 \'\'\' file = shelve.open("%sdata" % PATH) if name in list(file.keys()): data = file[name] else: data = None file.close() return data
#!/usr/bin/env python # _*_coding:utf-8_*_ # _author_=zh import os import locale import codecs import subprocess PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+os.sep+"home" def order(cmd): \'\'\' 执行命令结果输出到屏幕 :param cmd: 输入的命令 :return: \'\'\' word = subprocess.Popen(args=cmd, cwd=PATH, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) # 将结果decode输出,自动获取不同操作系统的默认编码 return word.stderr.read().decode(codecs.lookup(locale.getpreferredencoding()).name), \\ word.stdout.read().decode(codecs.lookup(locale.getpreferredencoding()).name)
import os import sys import socketserver import cmd import hmac PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.append(PATH) import db from conf import config class Myserver(socketserver.BaseRequestHandler): def handle(self): self.conn = self.request self.addr = self.client_address print("一个连接已进入") try: while True: # 客户端传入对应的方法名称,调用服务端相同的方法名 accept_data = self.conn.recv(1024) accept_data = accept_data.decode("utf-8") if accept_data in list(Myserver.__dict__.keys()): func = \'self.%s\' % accept_data eval(func)() else: print("服务端%s方法缺失" % accept_data) break except (ConnectionResetError, ConnectionAbortedError, SyntaxError): print("连接关闭") self.conn.close() def logon(self): # 登录,登录成功自动创建家目录,目录名为登录名 while True: accept_data = self.conn.recv(1024) accept_data = eval(accept_data.decode("utf-8")) list_data = db.data.read(accept_data[0]) if not list_data: self.conn.send("1".encode()) else: if accept_data == list_data: cmd.order("mkdir %s" % accept_data[0]) self.conn.send("0".encode()) break def login(self): # 注册 accept_data = self.conn.recv(1024) accept_data = eval(accept_data.decode("utf-8")) list_data = db.data.read(accept_data[0]) if list_data: self.conn.send("1".encode()) else: db.data.write(accept_data[0], accept_data) self.conn.send("0".encode()) def watch(self): # 查看登陆用户家目录下文件信息并返回给客户端 accept_data = self.conn.recv(1024) accept_data = eval(accept_data.decode("utf-8")) send_data = "%s %s%s" % (accept_data[0], info_list[3][1], accept_data[1]) eer, out = cmd.order(send_data) self.conn.send(("%s,%s" % (eer, out)).encode()) def upload(self): # 上传到登陆用户的家目录 accept_data = self.conn.recv(1024) accept_data = accept_data.decode("utf-8") accept_data = eval(accept_data) # accept_data = [length, file_name, logo_name] if int(info_list[2][1]) < int(accept_data[0]): self.conn.send("1".encode()) else: self.conn.send("0".encode()) path = info_list[3][1]+accept_data[2]+os.sep+accept_data[1] accept_data[0] = int(accept_data[0]) try: length = os.path.getsize(path) except FileNotFoundError: length = 0 if accept_data[0] == length: self.conn.send("None".encode()) else: accept_data[0] = accept_data[0]-length self.conn.sendall(("%s" % length).encode()) get_bytes = b\'\' while True: get_data = self.conn.recv(1024) if len(get_data) == accept_data[0]: get_bytes = get_data break else: get_bytes += get_data if len(get_bytes) == accept_data[0]: self.conn.send("0".encode()) break if length == 0: with open(path, "wb") as file: file.write(get_bytes) else: with open(path, "ab") as file: file.write(get_bytes) conf = hmac.new("file".encode()) with open(path, "rb") as file: data = file.read() conf.update(data) pwd = conf.hexdigest() get_pwd = (self.conn.recv(1024)).decode() if pwd == get_pwd: self.conn.send("0".encode()) else: self.conn.send("1".encode()) os.remove(path) def download(self): # 从登陆用户家目录下载文件,到指定目录 logo_name = (self.conn.recv(1024)).decode() file_path = info_list[3][1]+os.sep+logo_name send_data = "dir %s" % file_path eer, out = cmd.order(send_data) self.conn.send(("%s,%s" % (eer, out)).encode()) file_name = (self.conn.recv(1024)).decode() conf = hmac.new("file".encode()) if os.path.isfile(file_path+os.sep+file_name): with open(file_path+os.sep+file_name, "rb") as send_data: send_data = send_data.read() conf.update(send_data) pwd = conf.hexdigest() self.conn.send(("[\'%s\',\'%s\']" % (len(send_data), pwd)).encode()) sign = (self.conn.recv(1024)).decode() if sign == "0": self.conn.sendall(send_data) else: self.conn.send("1".encode()) if __name__ == \'__main__\': info = config.Configuration() info_list = info.get_config() server = socketserver.ThreadingTCPServer((info_list[0][1], int(info_list[1][1])), Myserver) server.serve_forever()
以上是关于FTP的主要内容,如果未能解决你的问题,请参考以下文章
七个办法只有一个有效:200 PORT command successful. Consider using PASV.425 Failed to establish connection.(代码片段