#server代码
import socketserver,os,hashlib
Base_paht = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/db'
class Server_ftp(socketserver.BaseRequestHandler):
def handle(self):
while 1:
try:
self.username = self.request.recv(1024).strip() #接受用户信息
if not self.username:continue
self.username_path = Base_paht + '/%s/' % self.username.decode() #获取用户文件地址
print(self.username.decode(), '连接成功!') #打印用户连接信息
self.request.send('连接服务器成功!'.encode())
while 1:
try:
self.data = self.request.recv(1024).strip() #接受客户端命令
print('-->',self.data)
if not self.data :continue
print('{} wrote:'.format(self.client_address[0]),self.username)#打印ip及用户名称
cmd_dic = self.data.decode() #命令编码
print('执行的命令为',cmd_dic)
if hasattr(self,cmd_dic + '_file'): #判断是否存在这条命令
self.request.send('{}命令可以被执行'.format(cmd_dic).encode())
func = getattr(self,cmd_dic + '_file') #反射
func()
else:
self.request.send('no'.encode()) #不存在发送错误信息
except ConnectionResetError as e:
# print('err',e)
break
except ConnectionResetError as e:
print(self.client_address[0],e)
break
def get_file(self):
filename = self.request.recv(1024).decode()
print('客户端想要获取的文件名称为:',filename)
if os.path.isfile(self.username_path + filename) :
file_size = os.stat(self.username_path + filename).st_size #确认文件大小
self.request.send(str(file_size).encode()) #发送文件大小
self.request.recv(1024) #接收please give me
f = open(self.username_path + filename,'rb')
self.request.send(f.read())
f.close()
confirm = self.request.recv(1024).decode()
print(confirm)
f_1 = open(self.username_path + filename, 'rb')
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f.close()
self.request.send(f_1_m2.encode())
print(self.request.recv(1024).decode())
else:
self.request.send('no'.encode()) #如果文件不存在,发送no信息
def put_file(self):
filename = self.request.recv(1024).decode()
if filename != 'no' :
self.request.send('服务器收到文件名称!'.encode())
file_size = self.request.recv(1024).decode()
self.request.send('服务器收到文件大小为{}'.format(file_size).encode())
f = open(self.username_path + filename,'wb') #直接写入,如果有就覆盖
confirm_size = 0
while confirm_size < int(file_size):
if int(file_size) - confirm_size > 1024: # 确保接受的准确性,拒绝粘包.
cal = 1024
else:
cal = int(file_size) - confirm_size
data = self.request.recv(cal)
confirm_size += len(data)
f.write(data)
f.close()
f_1 = open(self.username_path + filename,'rb')
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f_1.close()
self.request.send(f_1_m2.encode())
print(self.request.recv(1024).decode())
self.request.send('{}上传完成'.format(filename).encode()) # 返回服务器信息,表示下载完成
else:
print('客户端传送错误文件名称!')
def open_file(self):
filename = self.request.recv(1024).decode()
self.request.send('服务器收到目录名称!'.encode())
self.request.recv(1024) #防止粘包
if os.path.exists(self.username_path + filename ):
self.request.send('yes'.encode())
self.request.recv(1024)
path_dir = os.listdir(self.username_path+ filename)
if path_dir == []: # 如果为空
self.request.send('nothing'.encode())
else:
self.request.send(str(path_dir).encode())
else:
self.request.send('no'.encode())
def look_file(self):
self.request.recv(1024) #接收返回的数据,防止粘包
path_dir = os.listdir(self.username_path)
if path_dir == []: #如果为空
self.request.send('nothing'.encode())
else:
self.request.send(str(path_dir).encode())
if __name__ =='__main__':
HOST,PORT = 'localhost' , 6969
server = socketserver.ThreadingTCPServer((HOST,PORT),Server_ftp)
print('----------->等待连接<------------')
server.serve_forever()
#client代码
import socket,os,pickle,hashlib,sys
floder_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/user_floder'
user_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/conf'
server_db_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + '/server_ftp/db/'
class Scoket_ftp(object):
# 客户端类
def __init__(self):
self.client = socket.socket()
def client_user_register(self):
#用户注册
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
if not os.path.exists(user_path + '/%s'%username) :
pwd_md = hashlib.md5() #md5加密用户密码
pwd_md.update(bytes(password,encoding='utf-8'))
pwd_save = pwd_md.hexdigest()
pickle.dump({'username':username,'password':pwd_save},open(user_path + '/%s'%username,'wb'))
os.makedirs(server_db_path + username)
print('创建成功!')
else:
print('账户已经存在!')
def client_user_login(self):
#身份验证
username = input('请输入用户名:').strip()
password = input('请输入密码:').strip()
if os.path.exists(user_path + '/%s'%username) :
pwd_md = hashlib.md5() # md5加密用户密码
pwd_md.update(bytes(password,encoding='utf-8'))
pwd_save = pwd_md.hexdigest()
user_dic = pickle.load(open(user_path + '/%s'%username,'rb'))
if username == user_dic['username'] and pwd_save == user_dic['password'] :
print('%s登录成功'%username)
return username
else:
print('账户密码错误!')
return False
else:
print('账户密码错误!')
return False
def client_conn(self,ip_addr,port):
#建立连接
while 1:
username = self.client_user_login()
if username :
self.client.connect((ip_addr, port))
self.client.send(username.encode())
print(self.client.recv(1024).decode())
break
else:
continue
def help(self):
#帮助信息
print('''
-----------help-----------
look:查看当前目录下文件
open foldername:打开文件夹
get filename:下载文件
put filename:上传文件
''')
def client_interaction(self):
#交互
while 1:
self.help()
cmd = input('请输入操作命令:').strip()
if len(cmd.split()) == 1: #判断命令行长度,如果是1的话,在判断输入
if cmd == 'look':
self.file_look()#使用look方法
elif cmd == 'exit':
self.file_exit()
else:
print('命令输入错误,请重新输入')
continue
elif len(cmd.split()) == 2: #长度为2,证明是带有前面的语句的
cmd_option, filename = cmd.split()
if hasattr(self,'file_' + cmd_option):
func = getattr(self,'file_' +cmd_option)
func(filename)
else:
continue
else:
continue
def file_look(self):
#查看
self.client.send('look'.encode()) #发送方法
print(self.client.recv(1024).decode()) # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
self.client.send('please give me!'.encode()) # 自动发送给服务器
print('文件目录:',self.client.recv(1024).decode()) #接收目录信息并打印
def file_get(self,filename):
#下载
self.client.send('get'.encode()) #先发送方法
print(self.client.recv(1024).decode()) #服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
self.client.send(filename.encode()) #再发送文件名称
confirm = self.client.recv(1024).decode() #服务器确认文件是否存在,如果存在返回文件大小,如果不存在,返回no
if confirm != 'no':
self.client.send('please give me!'.encode())
f = open(floder_path+'/'+filename,'wb') #在下载文件夹中创建该文件(如果存在,则替换)
confirm_cal = 0
rate = 1
while confirm_cal < int(confirm):
if int(confirm) - confirm_cal > 1024: #确保接受的准确性,拒绝粘包.
cal = 1024
else:
cal = int(confirm) - confirm_cal
data = self.client.recv(cal)
confirm_cal += len(data) #避免tcp拆包
f.write(data)
if int(confirm) > 102400:
if confirm_cal > int(confirm)/100*(rate+1) and rate<= 100 :
rate += 1
r = '\r[%s]%d%%' % ("=" * rate, rate)
sys.stdout.write(r)
sys.stdout.flush()
else:
continue
else:
r = '[%s]%d%%'%('='*100,100)
sys.stdout.write(r)
f.close()
self.client.send('{}下载完成'.format(filename).encode()) # 返回服务器信息,表示下载完成
f_1 = open(floder_path+'/'+filename,'rb') #判断一致性
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f_1.close()
f_1_m2_server = self.client.recv(1024).decode()
if f_1_m2 == f_1_m2_server :
print('\n下载完成!')
self.client.send('客户端已经成功获取完整文件!'.encode())
else:
print('传输异常')
self.client.send('客户端获取文件不完整或存在异常!'.encode())
else:
print('确认信息为no,文件可能不存在或有其他问题!')
def file_put(self,filename):
#上传文件
self.client.send('put'.encode()) # 先发送方法
print(self.client.recv(1024).decode()) # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
if os.path.isfile(floder_path + '/' + filename):
self.client.send(filename.encode())
print(self.client.recv(1024).decode()) #拒绝粘包
cal = os.stat(floder_path + '/' + filename).st_size #获取文件大小
self.client.send(str(cal).encode()) #发送文件大小信息
print(self.client.recv(1024).decode()) #获取反馈
f = open(floder_path+'/'+filename,'rb') #打开文件
self.client.send(f.read())
f.close()
f_1 = open(floder_path + '/' + filename, 'rb') #一致性校验
m2 = hashlib.md5()
m2.update(f_1.read())
f_1_m2 = m2.hexdigest()
f_1.close()
f_1_m2_server = self.client.recv(1024).decode()
if f_1_m2 == f_1_m2_server:
print('上传完成!')
self.client.send('客户端已经成功上传完整文件!'.encode())
else:
print('传输异常')
self.client.send('客户端上传文件不完整或存在异常!'.encode())
print(self.client.recv(1024).decode())
else:
self.client.send('no'.encode())
print('查无此文件')
def file_open(self,filename):
self.client.send('open'.encode()) # 先发送方法
print(self.client.recv(1024).decode()) # 服务器确认信息,后面可以加入判断,判断服务器目前状态是否正常
self.client.send(filename.encode()) #发送目录名称
print(self.client.recv(1024).decode())
self.client.send('防止粘包'.encode())
confirm = self.client.recv(1024).decode() # 服务器确认文件是否存在,如果存在返回yes,如果不存在,返回no
if confirm != 'no':
self.client.send('please give me!'.encode()) #自动发送给服务器
file_dir = self.client.recv(1024).decode()
print(file_dir)
else:
print('确认信息为no,目录可能不存在或有其他问题!')
if __name__ == '__main__' :
socket_ftp = Scoket_ftp()
option = input('''
---------option----------
1.创建用户
2.登录
3.退出
''').strip()
if option == '1':
socket_ftp.client_user_register()
elif option == '2':
socket_ftp.client_conn('localhost',6969)
socket_ftp.client_interaction()
elif option == '3':
exit()
else:
print('wrong!')
exit()