#client代码
importsocket,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/'
classScoket_ftp(object):#客户端类
def __init__(self):
self.client=socket.socket()defclient_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('账户已经存在!')defclient_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)returnusernameelse:print('账户密码错误!')returnFalseelse:print('账户密码错误!')returnFalsedefclient_conn(self,ip_addr,port):#建立连接
while 1:
username=self.client_user_login()ifusername :
self.client.connect((ip_addr, port))
self.client.send(username.encode())print(self.client.recv(1024).decode())break
else:continue
defhelp(self):#帮助信息
print('''-----------help-----------
look:查看当前目录下文件
open foldername:打开文件夹
get filename:下载文件
put filename:上传文件''')defclient_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
deffile_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()) #接收目录信息并打印
deffile_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 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+= 1r= '\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,文件可能不存在或有其他问题!')deffile_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('查无此文件')deffile_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()