项目开发目录
FTPClient
bin文件夹 Client.py
import socket, os, sys
PATH = os.path.dirname(os.path.dirname(__file__))
sys.path.append(PATH)
class FTPclient():
def __init__(self):
from optparse import OptionParser
opt = OptionParser()
opt.add_option("-H", dest="HOST", help="FTP Server HOST")
opt.add_option("-P", dest="PORT", type="int", help="FTP Serve PORT")
values, args = opt.parse_args()
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect(values)
self.user = None
self.show = None
def connect(self, values):
HOST = values.HOST
PORT = values.PORT
if HOST and PORT:
self.client.connect((HOST, PORT))
print("connect succeed")
self.login()
else:
exit("ERROR: should supply HOST and PORT !")
def login(self):
count = 3
while count > 0:
username = input("please enter your username>>: ").strip()
password = input("enter your password>>: ").strip()
sql = "select password from user where username = %s"
from core import connect_database
cursor = connect_database.connect()
rows = cursor.execute(sql, (username))
if rows == 0:
count -= 1
print("用户名错误,请重新输入,您还有{}次机会重新输入".format(count))
elif rows != 0:
res = cursor.fetchall()[0].get("password")
if res != password:
count -= 1
print("密码错误,请重新输入,您还有{}次机会重新输入".format(count))
else:
print("登录成功")
self.user = username
from log import log
log.log(self.user, "login", self.user)
msg_dic = self.make_dict(action="log", username=username)
self.send_msg(msg_dic)
msg_dic = self.recv_msg()
self.show = msg_dic.get("show")
self.handle()
def make_dict(self, action,**kwargs)-> dict:
msg_dic = {
"action": action
}
msg_dic.update(**kwargs)
return msg_dic
def send_msg(self, msg_dic)->None:
import struct,json
str_msg = json.dumps(msg_dic)
length = struct.pack("q", len(str_msg))
self.client.send(length)
self.client.send(str_msg.encode("utf-8"))
def recv_msg(self)->dict:
length_dic = self.client.recv(8)
import struct,json
str_dic_length = struct.unpack("q", length_dic)[0]
str_dic = self.client.recv(str_dic_length)
dic = json.loads(str_dic)
return dic
def handle(self):
"""和服务端交互"""
while True:
cmd = input("{}>>: ".format(self.show)).strip()
cmd_list = cmd.split(" ")
if len(cmd_list) > 1:
action = cmd_list[0]
content = cmd_list[1]
else:
action = cmd_list[0]
content = ""
if hasattr(self, action):
func = getattr(self, action)
func(content)
def md(self, content):
"""在服务端家目录"""
msg_dic = self.make_dict(action="md", content=content)
self.send_msg(msg_dic=msg_dic)
recv_dic = self.recv_msg()
print(recv_dic.get("stdout"), recv_dic.get("stderr"))
from log import log
log.log(self.user, "md", content)
def dir(self, content):
"""查看服务端用户当前路径"""
msg_dic = self.make_dict(action="dir", content=content)
self.send_msg(msg_dic=msg_dic)
recv_dic = self.recv_msg()
print(recv_dic.get("stdout"), recv_dic.get("stderr"))
from log import log
log.log(self.user, "dir", content)
def cd(self, content):
"""切换用户在服务端目录"""
msg_dic = self.make_dict(action="cd", content=content)
self.send_msg(msg_dic=msg_dic)
recv_dic = self.recv_msg()
if recv_dic.get("status_code") == 100:
self.show = recv_dic.get("show")
from log import log
log.log(self.user, "cd", content)
else:
print(recv_dic.get("status_msg"))
def download(self, content):
"""从服务端下载文件"""
msg_dic= self.make_dict(action="download", file_name=content)
self.send_msg(msg_dic=msg_dic)
recv_dic = self.recv_msg()
if recv_dic.get("status_code") == 102:
file_path = recv_dic.get("file_path")
file_size = recv_dic.get("file_size")
import time
from config import setting
now = str(time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime(time.time())))
download_file_path = setting.DOWNLOAD_PATH + "\\" + content + "." + now + ".download"
with open(download_file_path, "wb") as f:
sql = "insert into UNDOWNLOAD_FILE(username, file_name, file_path, file_size) values(%s, %s, %s, %s)"
from core import connect_database
cursor = connect_database.connect()
cursor.execute(sql, (self.user, content + "." + now + ".download", file_path, file_size))
recv_size = 0
while recv_size < file_size:
recv_content = self.client.recv(1024)
f.write(recv_content)
recv_size += len(recv_content)
print("下载进度:{}{}%".format("#" * int(int(int(recv_size) / int(file_size)) * 100 / 2), int(int(recv_size) / int(file_size)) * 100), flush=True, end="\r")
print("\n下载完成!!!")
sql = "delete from UNDOWNLOAD_FILE where username = %s and file_name = %s"
cursor.execute(sql, (self.user, content + "." + now + ".download"))
if not os.path.exists(setting.DOWNLOAD_PATH + "\\" + content):
os.rename(download_file_path, setting.DOWNLOAD_PATH + "\\" + content)
else:
download_file_path_ = download_file_path.replace(".download", "")
os.rename(download_file_path, download_file_path_)
from log import log
log.log(self.user, "download", content)
else:
print(recv_dic.get("status_msg"))
def download_bar(self, recv_size, file_size):
recv_size = int(recv_size)
file_size = int(file_size)
if recv_size < file_size:
print("下载进度:{}{}%".format("#" * int(int(int(recv_size) / int(file_size)) * 100 / 2), int(int(recv_size) / int(file_size)) * 100), flush=True, end="\r")
def re_get(self, content):
"""断点续存"""
while True:
from core import connect_database
cursor = connect_database.connect()
sql = "select id,file_name from undownload_file where username = %s"
cursor.execute(sql, (self.user))
res = cursor.fetchall()
tips = """--------------------------
id file_name"""
print(tips)
for i in res:
id = i.get("id")
file_name = i.get("file_name")
tips = """--------------------------
{} {}""".format(id, file_name)
print(tips)
input_id = input("please enter the id to download file(enter 'exit' to exit):>> ").strip()
if input_id == "exit":
break
elif input_id.isdigit():
input_id = int(input_id)
sql = "select file_name,file_path,file_size from undownload_file where id = %d" % input_id
cursor.execute(sql)
res = cursor.fetchall()[0]
file_name = res.get("file_name")
file_path = res.get("file_path")
file_size = res.get("file_size")
from config import setting
if os.path.exists(setting.DOWNLOAD_PATH + "\\" + file_name):
recv_size = os.path.getsize(setting.DOWNLOAD_PATH + "\\" + file_name)
msg_dic = self.make_dict(action="re_get", file_name=file_name, file_path=file_path, file_size=file_size, recv_size=recv_size)
self.send_msg(msg_dic=msg_dic)
recv_dic = self.recv_msg()
if recv_dic.get("status_code") == 102:
with open(setting.DOWNLOAD_PATH + "\\" + file_name, "wb") as f:
while int(recv_size) < int(file_size):
recv_content = self.client.recv(1024)
f.write(recv_content)
recv_size += len(recv_content)
print("下载进度:{}{}%".format("#" * int(int(int(recv_size) / int(file_size)) * 100 / 2), int(int(recv_size) / int(file_size)) * 100), flush=True, end="\r")
print("\n下载完成!!!")
if not os.path.exists(setting.DOWNLOAD_PATH + "\\" + ".".join(file_name.split(".")[0:2])):
os.rename(setting.DOWNLOAD_PATH + "\\" + file_name, setting.DOWNLOAD_PATH + "\\" + ".".join(file_name.split(".")[0:2]))
else:
download_file_path_ = (setting.DOWNLOAD_PATH + "\\" + file_name).replace(".download", "")
os.rename((setting.DOWNLOAD_PATH + "\\" + file_name), download_file_path_)
else:
print(recv_dic.get("status_msg"))
sql = "delete from undownload_file where id = %d" % input_id
cursor.execute(sql)
from log import log
log.log(self.user, "re_get", file_name)
else:
print("enter wrong")
continue
client = FTPclient()
config 文件夹 setting.py 文件
import os
DOWNLOAD_PATH = os.path.dirname(os.path.dirname(__file__)) + "\\" + "download"
core 文件夹 connect_database.py 文件
def connect():
import pymysql
conn = pymysql.connect(
host="localhost",
port=3306,
database="FTP",
user="root",
password="",
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
return cursor
log文件夹 log.py 文件
def log(username, action, msg):
from core import connect_database
cursor = connect_database.connect()
sql = "insert into user_log(username, action, msg) values(%s, %s, %s)"
cursor.execute(sql, (username, action, msg))
if __name__ == '__main__':
import pymysql
conn = pymysql.connect(
host="localhost",
port=3306,
database="FTP",
user="root",
password="",
charset='utf8',
autocommit=True
)
cursor = conn.cursor()
import xlwt
book = xlwt.Workbook(encoding="utf-8", style_compression=0)
sheet = book.add_sheet("日志", cell_overwrite_ok=True)
col = ["用户名", "进行的操作", "操作的信息", "操作时间"]
for i in range(0, len(col)):
sheet.write(0, i, col[i])
sql = 'select username,action,msg,time from user_log'
cursor.execute(sql)
res = cursor.fetchall()
import datetime
for i in range(0, len(res)):
for j in range(0, 4):
sheet.write(i+1, j, res[i][j])
if j == 3:
sheet.write(i+1, j, res[i][j].strftime('%Y-%m-%d %H:%M:%S'))
book.save("log.xls")
FTPServer
bin文件夹 main.py文件
import sys,os
path = os.path.dirname(os.path.dirname(__file__))
if __name__ == '__main__':
sys.path.append(path)
from lib import management
server = management.Management(sys.argv)
config 文件夹 setting.py 文件
HOST = "127.0.0.1"
PORT = 8080
import os
USER_HOME = os.path.dirname(os.path.dirname(__file__)) + "\\home"
core 文件夹 connect_database 文件
def connect():
import pymysql
conn = pymysql.connect(
host = "localhost",
port = 3306,
database = "FTP",
user = "root",
password = "",
charset='utf8',
autocommit=True
)
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
return cursor
core 文件夹 FTP.sql 文件
create database FTP;
use FTP;
create table USER(
id int primary key auto_increment,
username varchar(16),
password varchar(16)
);
create table LOG(
id int primary key auto_increment,
username varchar(16),
action varchar(16),
msg varchar(64),
time timestamp not null default CURRENT_TIMESTAMP
);
create table USER_LOG(
id int primary key auto_increment,
username varchar(16),
action varchar(16),
msg varchar(64),
time timestamp not null default CURRENT_TIMESTAMP
);
create table UNDOWNLOAD_FILE(
id int primary key auto_increment,
username varchar(16),
file_name varchar(16),
file_path varchar(1024),
file_size varchar(32)
);
lib文件夹 managment.py文件
import socketserver
class Management():
def __init__(self, argv):
cmd = argv[1]
if hasattr(self, cmd):
func = getattr(self, cmd)
func()
else:
self.tips()
def tips(self):
tip = """
----------------------------------------
FTP Project Command List
----------------------------------------
run start up FTP Server
----------------------------------------
create create FTP User
----------------------------------------
delete delete FTP User
----------------------------------------
tips FTP Command tip
----------------------------------------
"""
exit(tip)
def run(self):
from lib import Server
from config import setting
print("{}FTPServer Run {} {} {}".format("-"*25, setting.HOST, setting.PORT, "-"*25))
server = socketserver.ThreadingTCPServer(("127.0.0.1", 8080), Server.FTPserver)
server.serve_forever()
def create(self):
from core import connect_database
cursor = connect_database.connect()
username = input("username: ").strip("")
password = input("password: ").strip("")
sql = "select * from user where username = %s"
res = cursor.execute(sql, (username))
if res == 0:
sql = "insert into user(username, password) values(%s, %s)"
cursor.execute(sql, (username, password))
print("用户创建成功!!!")
from log import log
action = "login"
log.log(username, action, username)
else:
print("该用户已存在!!!")
def delete(self):
from core import connect_database
cursor = connect_database.connect()
username = input("username: ").strip("")
sql = "select * from user where username = %s"
rows = cursor.execute(sql, (username))
if rows != 0:
sql = "delete from user where username = %s"
cursor.execute(sql, (username))
print("删除用户成功!!!")
from log import log
action = "delete"
log.log("", action, username)
else:
print("要删除的用户不存在!!!")
lib 文件夹 Server.py 文件
import socketserver,time
STATUS_MSG = {
000: "nothing",
100: "cd dir success!!!",
101: "the dir not exist!!!",
102: "file exits!!!",
103: "file not exits!!!",
}
class FTPserver(socketserver.BaseRequestHandler):
def handle(self) -> None:
print("{}连接成功".format(self.client_address))
while True:
msg_dic = self.recv_msg()
action = msg_dic.get("action")
if hasattr(self, "_%s" % action):
func = getattr(self, "_%s" % action)
func(msg_dic)
def recv_msg(self)->dict:
length_dic = self.request.recv(8)
import struct,json
str_dic_length = struct.unpack("q", length_dic)[0]
str_dic = self.request.recv(str_dic_length)
dic = json.loads(str_dic)
return dic
def make_dict(self, status_code, **kwargs)-> dict:
msg_dic = {
"status_code": status_code,
"status_msg": STATUS_MSG.get(status_code)
}
msg_dic.update(**kwargs)
return msg_dic
def send_msg(self, msg_dic)->None:
import struct,json
str_msg = json.dumps(msg_dic)
length = struct.pack("q", len(str_msg))
self.request.send(length)
self.request.send(str_msg.encode("utf-8"))
def _log(self, msg_dic):
self.username = msg_dic.get("username")
from config import setting
user_path = setting.USER_HOME + "\\" + self.username
self.current_path = user_path
import os
if not os.path.exists(user_path):
os.makedirs(user_path)
self.show = user_path.replace(setting.USER_HOME, "")
dic = self.make_dict(status_code=000, show=self.show)
self.send_msg(msg_dic=dic)
def _md(self, msg_dic):
content = msg_dic.get("content")
import subprocess
s = subprocess.Popen("md {}".format(self.current_path + "\\" + content), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = s.stdout.read()
stderr = s.stderr.read()
msg_dic = self.make_dict(status_code=000, stdout=stdout.decode("gbk"), stderr=stderr.decode("gbk"))
self.send_msg(msg_dic=msg_dic)
def _dir(self, msg_dic):
import subprocess
s = subprocess.Popen("dir {}".format(self.current_path), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = s.stdout.read()
stderr = s.stderr.read()
msg_dic = self.make_dict(status_code=000, stdout=stdout.decode("gbk"), stderr=stderr.decode("gbk"))
self.send_msg(msg_dic=msg_dic)
def _cd(self, msg_dic):
path = self.current_path + "\\" + msg_dic.get("content")
import os
path = os.path.abspath(path)
from config import setting
if (setting.USER_HOME + "\\" + self.username) in path and os.path.exists(path):
import subprocess
s = subprocess.Popen("cd {}".format(path), shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stdout = s.stdout.read()
stderr = s.stderr.read()
self.show = path.replace(setting.USER_HOME + "\\" + self.username, "")
msg_dic = self.make_dict(status_code=100, stdout=stdout.decode("gbk"), stderr=stderr.decode("gbk"), show=self.show)
self.send_msg(msg_dic=msg_dic)
self.current_path = path
else:
msg_dic = self.make_dict(status_code=101)
self.send_msg(msg_dic=msg_dic)
def _download(self, msg_dic):
"""下载文件"""
file_name = msg_dic.get("file_name")
file_path = self.current_path + "\\" + file_name
import os
if os.path.exists(file_path):
file_size = os.path.getsize(file_path)
msg_dic = self.make_dict(status_code=102, file_path=file_path, file_size=file_size)
self.send_msg(msg_dic=msg_dic)
with open(file_path, "rb") as f:
for line in f:
self.request.send(line)
else:
msg_dic = self.make_dict(status_code=103)
self.send_msg(msg_dic=msg_dic)
def _re_get(self, msg_dic):
"""断点续存"""
file_path = msg_dic.get("file_path")
file_size = msg_dic.get("file_size")
recv_szie = msg_dic.get("recv_size")
import os
if os.path.exists(file_path) and int(file_size) == int(os.path.getsize(file_path)):
msg_dic = self.make_dict(status_code=102)
self.send_msg(msg_dic=msg_dic)
with open(file_path, "rb") as f:
f.seek(recv_szie)
for line in f:
self.request.send(line)
else:
msg_dic = self.make_dict(status_code=103)
self.send_msg(msg_dic=msg_dic)
log 文件夹 log.py 文件
def log(username, action, msg):
from core import connect_database
cursor = connect_database.connect()
sql = "insert into log(username, action, msg) values(%s, %s, %s)"
cursor.execute(sql, (username, action, msg))
代码演示
创建用户
用户登录
删除用户
切换目录、下载文件、断点续存
生成日志文件