import optparse
import socket
import json
import re
import os
import sys
STATUS_CODE={
250:"Invalid cmd format,e.g:{'action':'get','filename':'test.py','size':344}",
251:"Invalid cmd",
252:"Invalid auth data",
253:"Wrong username or password",
254:"Passed authentication",
255:"Filename doesn't provided",
256:"File doesn't exist on server",
257:"ready to send file",
258:"md5 verification",
800:"the file exist,but not enough,is continue",
801:"the file exist",
802:"ready to receive datas",
900:"md5 valdate success",
}
class ClientHandler():
def __init__(self):
self.op=optparse.OptionParser()
self.op.add_option('-S','--server',dest='server')
self.op.add_option('-P', '--port', dest='port')
self.op.add_option('-u', '--username', dest='username')
self.op.add_option('-p', '--password', dest='password')
self.options, self.args = self.op.parse_args()
#上传文件的绝对路径
#os.path.abspath(__file__):获得当前文件的绝对路径
# os.path.dirname(os.path.abspath(__file__)):获得上一级目录
self.mainPath=os.path.dirname(os.path.abspath(__file__))
self.last = 0
#下面两个函数是实例化类的时候就执行
#对参数进行处理
self.verify_args(self.options)
#连接服务端,进行用户操作
self.make_connection()
# 对参数进行处理
def verify_args(self,options):
server=options.server
port=options.port
username=options.username
password=options.password
#对参数进行简单判断
if re.match(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",str(server)):
return True
else:
exit("IP vaild")
if int(port) and int(port) < 65535:
return True
else:
exit("the port is in 0-65535")
if username is None:
return True
else:
exit("用户名为空")
if password is None:
return True
else:
exit("密码为空")
#连接服务端
def make_connection(self):
#创建socket
self.sock=socket.socket()
self.sock.connect((self.options.server,int(self.options.port)))
# 用户操作
def interactive(self):
#先进行身份认证
if self.authenticate():
print('''请选择你要进行的操作:
1.上传文件示例:put filename file
2.查看文件:ls
3.进入目录:cd dirname
4.创建目录:mkdir dirname
5.退出:quit
''')
while 1:
cmd_info=input("[%s]:"%self.user).strip()#put test.py file
cmd_list=cmd_info.split()#默认以空格分隔
if cmd_list[0]=="quit":break
if hasattr(self,cmd_list[0]):
func=getattr(self,cmd_list[0])
func(*cmd_list)
#传输文件的路径必须和客户端路径同级
def put(self,*cmd_list):
action,local_path,target_path=cmd_list
print( action,local_path,target_path)
# os.path.join(self.mainPath, local_path):self.mainPath+local_path得到本地完全的图片的路径
#这里首先对格式进行判断
#获取文件完整路径
local_path=os.path.join(self.mainPath,local_path)
#获取文件的名字
file_name=os.path.basename(local_path)
#获取文件大小
file_size=os.stat(local_path).st_size
data = {
'action': 'put',
'file_name':file_name,
'file_size':file_size,
'target_path':target_path#类型
}
has_sent=0
self.sock.send(json.dumps(data).encode('utf-8'))
is_exist=int(self.sock.recv(1024).decode("utf-8"))
if is_exist==800:
print(STATUS_CODE[is_exist])
choice=input('请输入你的选择是否选择续传:[Y/N]')
if choice.upper()=="Y":
self.sock.sendall("Y".encode("utf8"))
continue_position=self.sock.recv(1024).decode("utf8")
has_sent+=int(continue_position)
else:
self.sock.sendall("N".encode("utf8"))
elif is_exist==801:
print(STATUS_CODE[is_exist])
return
else:
print(STATUS_CODE[is_exist])
f=open(local_path,"rb")
#将光标的位置调整到has_sent
f.seek(has_sent)
while has_sent<file_size:
data=f.read(1024)
self.sock.sendall(data)
has_sent+=len(data)
self.show_progress(has_sent,file_size)
f.close()
def show_progress(self,has,total):
rate=float(has)/float(total)
rate_num=int(rate*100)
sys.stdout.write("%s%% %s
"%(rate_num,"#"* rate_num))
def ls(self,*cmd_list):
data= {
'action': 'ls',
}
self.sock.sendall((json.dumps(data).encode("utf8")))
reponse=self.sock.recv(1024).decode("utf8")
print(reponse)
def cd(self,*cmd_list):
data={
'action': 'cd',
'dirname':cmd_list[1]
}
self.sock.sendall((json.dumps(data).encode("utf8")))
reponse = self.sock.recv(1024).decode("utf8")
# self.current_dir=reponse
print("当前目录:"+str(reponse))
def mkdir(self,*cmd_list):
data = {
'action': 'mkdir',
'dirname': cmd_list[1]
}
self.sock.sendall((json.dumps(data).encode("utf8")))
reponse = self.sock.recv(1024).decode("utf8")
print(reponse)
#身份认证
def authenticate(self):
#如果用户名或者密码有一个为空,则要求再次输入,反之进入下一步
if self.options.username is None or self.options.password is None:
username=input('username:')
password=input('password')
return self.get_auth_result(username,password)
return self.get_auth_result(self.options.username,self.options.password)
#发送认证信息
def get_auth_result(self,username,password):
# 构建数据
dic={
'action':'auth',
'username':username,
'password':password
}
#发送认证信息
self.sock.send(json.dumps(dic).encode('utf-8'))
#判断服务端回复信息,进行认证
response=self.response()
if response['status_code']==254:
self.user=username
self.current_dir=username
print(STATUS_CODE[254])
else:
print(response['status_code']+response['status_mes'])
return True
#接收信息
def response(self):
data = self.sock.recv(1024).decode('utf-8')
data = json.loads(data)
return data
ch=ClientHandler()
# 用户操作,在用户操作里面会进行身份认证
ch.interactive()