python高级ftp开发_python第四十八天--高级FTP

1 #!usr/bin/env python

2 #-*-coding:utf-8-*-

3 #Author calmyan

4 importsocket,os,json,getpass,hashlib5 importos ,sys,optparse6

7 STATUS_CODE={8 240:'格式出错,格式:{"action":"get","filename":"filename","size":100}',9 241:'指令错误',10 242:'用户密码出错',11 243:'用户或密码出错',12 244:'用户密码通过校验',13 }14 BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#获取相对路径转为绝对路径赋于变量

15 sys.path.append(BASE_DIR)#增加环境变量

16 from cfg importconfig17 classFTPClient(object):18 def __init__(self):19 paresr=optparse.OptionParser()20 paresr.add_option('-s','--server',dest='server',help='服务器地址')21 paresr.add_option('-P','--port',type="int",dest='port',help='服务器端口')22 paresr.add_option('-u','--username',dest='username',help='用户名')23 paresr.add_option('-p','--password',dest='password',help='密码')24 (self.options,self.args)=paresr.parse_args()#返回一个字典与列表的元组

25 self.verify_args(self.options,self.args)#判断参数

26 self.ser_connect()#连接服务端

27 self.cmd_list=config.CMD_LIST28 self.rat=0#文件断点

29

30 #实例化一个连接端

31 defser_connect(self):32 self.c=socket.socket()#实例化一个连接端

33 self.c.connect((self.options.server,self.options.port))#进行连接

34

35 #判断用户与密码是否成对出现

36 defverify_args(self,options,args):37 if (options.username is None and options.password is None) or (options.username is not None and options.password is not None):#判断用户与密码是否成对出现

38 pass##判断用户与密码单个出现

39 else:40 exit('出错:请输入用户与密码!')#退出

41 if options.server and options.port:#端口判断

42 if options.port>0 and options.port<65535:43 returnTrue44 else:45 print('端口号:[%s]错误,端口范围:0-65535'%options.port)46

47 #登陆方法

48 def landing(self):#登陆方法

49 '''用户验证'''

50 if self.options.username is not None:#判断用户名已经输入

51 #print(self.options.username,self.options.password)

52 return self.get_user_pwd(self.options.username,self.options.password)#返回结果

53 else:54 print('用户登陆'.center(60,'='))55 ret_count=0#验证次数

56 while ret_count<5:57 username=input('用户名:').strip()58 password=getpass.getpass('密码:').strip()59 ifself.get_user_pwd(username,password):60 return self.get_user_pwd(username,password)#调用远程验证用户 返回结果

61 else:62 ret_count+=1#次数加一

63 print('认证出错次数[%s]'%ret_count)64 else:65 print('密码出错次数过多!')66 exit()67

68 #'''用户名与密码检验'''

69 defget_user_pwd(self,username,password):70 '''用户名与密码检验'''

71 #发送 头文件

72 data={73 'action':'auth',74 'username':username,75 'password':password76 }77 self.c.send(json.dumps(data).encode())#发送到服务器

78 response = self.get_response()#得到服务端的回复

79 if response.get('status_code') == 244:80 print(STATUS_CODE[244])81 self.user = username#存下用户名

82 self.user_dir=response.get('dir')#目录

83 returnTrue84 else:85 print(response.get("status_msg") )86

87 #服务器回复

88 def get_response(self):#服务器回复

89 '''服务器回复信息'''

90 data=self.c.recv(1024)#接收回复

91 data =json.loads(data.decode())92 returndata93

94 #指令帮助

95 def help(self):#指令帮助

96 attr='''

97 help 指令帮助98 ----------------------------------99 info 个人信息100 ----------------------------------101 ls 查看当前目录(linux/windows)102 ----------------------------------103 pwd 查看当前路径(linux/windows)104 ----------------------------------105 cd 目录 切换目录(linux/windows)106 ----------------------------------107 get filename 下载文件108 ----------------------------------109 put filename 上传文件110 ----------------------------------111 --md5 使用md5 在get/put 后112 ----------------------------------113 mkdir name 创建目录(linux/windows)114 ----------------------------------115 rmdir name 删除目录(linux/windows)116 ----------------------------------117 rm filename 删除文件 (linux/windows)118 ----------------------------------119 exit 退出120 ----------------------------------121 '''.format()122 print(attr)123

124 ##交互

125 def inter(self):#交互

126 if self.landing():#通过用户密码认证

127 print('指令界面'.center(60,'='))128 self.help()129 whileTrue:130 cmd = input('[%s]-->指令>>>:'%self.user_dir).strip()131 if len(cmd)==0:continue#输入空跳过

132 if cmd=='exit':exit()#退出指令

133 cmd_str=cmd.split()#用空格分割 取命令到列表

134 #print(cmd_str)

135 #print(len(cmd_str))

136 if len(cmd_str)==1 and cmd_str[0] in self.cmd_list:#如果是单个命令 并且在命令列表中

137 #if len(cmd_str)==1:#如果是单个命令 并且在命令列表中

138 if cmd_str[0]==config.HELP:139 self.help()140 continue

141 func=getattr(self,'cmd_compr')#调用此方法

142 ret=func(cmd_str)143 ifret:144 continue

145 else:146 pass

147 elif len(cmd_str)>1:148 if hasattr(self,'cmd_%s'%cmd_str[0]):#判断类中是否有此方法

149 func=getattr(self,'cmd_%s'%cmd_str[0])#调用此方法

150 func(cmd_str)#执行

151 continue

152 else:153 print('指令出错!')154 self.help()#155

156 #'''是否要md5'''

157 defcmd_md5_(self,cmd_list):158 '''是否要md5'''

159 if '--md5' incmd_list:160 returnTrue161

162 #进度条

163 def show_pr(self,total):#进度条

164 received_size = 0 #发送的大小

165 current_percent = 0 #166 while received_size <167 if int total>current_percent :168 print("#",end="",flush=True)#进度显示167>

169 current_percent = int((received_size / total) * 100)170 new_size = yield #断点跳转 传入的大小

171 received_size +=new_size172

173 #单个命令

174 def cmd_compr(self,cmd_str,**kwargs):175 mag_dict={176 "action":"compr",177 'actionname':cmd_str[0]178 }179 self.c.send(json.dumps(mag_dict).encode('utf-8'))#发送数据

180 cmd_res_attr=self.get_response()#得到服务器的回复

181 if type(cmd_res_attr) is not int:#如果不int 类型

182 if cmd_res_attr["status_code"] ==241:#命令不对

183 print(cmd_res_attr['status_msg'])184 return

185 if cmd_res_attr["status_code"] ==240:#命令不对

186 print(cmd_res_attr['status_msg'])187 return

188 size_l=0#收数据当前大小

189 self.c.send('准备好接收了,可以发了'.encode('utf-8'))190 receive_data= ''.encode()191 while size_l<192 data="self.c.recv(1024)#开始接收数据</p">

193 size_l+=len(data)#加上

194 receive_data +=data195 else:196 receive_data=receive_data.decode()197 try:198 receive_data=eval(receive_data)#转为列表 或字典

199 exceptException as e:200 pass

201 if type(receive_data) is dict:#如果是字典

202 for i inreceive_data:203 print(i,receive_data[i])204 return 1

205 if type(receive_data) is list:#如果是列表

206 for i inreceive_data:207 print(i)208 return 1

209 print(receive_data)210 return 1

211

212 #切换目录

213 def cmd_cd(self,cmd_list,**kwargs):214 '''切换目录'''

215 mag_dict={216 "action":"cd",217 'actionname':cmd_list[1]218 }219 self.c.send(json.dumps(mag_dict).encode('utf-8'))#发送数据

220 msg_l=self.c.recv(1024)#接收数据 消息

221 data=json.loads(msg_l.decode())222 if data["status_code"] ==251:#目录不可切换

223 print(data['status_msg'])224 return

225 elif data["status_code"] ==252:#目录可以换

226 print(data['status_msg'])227 self.c.send(b'1')#发送到服务器,表示可以了

228 data=self.c.recv(1024)229 print(data.decode())230 user_dir=data.decode()231 print(user_dir)232 self.user_dir=user_dir233 return

234 elif data["status_code"] ==256:#目录不存在

235 print(data['status_msg'])236 return

237

238 #删除文件

239 def cmd_rm(self,cmd_list,**kwargs):240 mag_dict={241 "action":"rm",242 'filename':cmd_list[1]243 }244 self.c.send(json.dumps(mag_dict).encode('utf-8'))#发送文件信息

245 data=self.get_response()#得到服务器的回复

246 if data["status_code"] ==245:#文件不存在

247 print(data['status_msg'])248 #print('删除前空间:',data['剩余空间'])

249 return

250 elif data["status_code"] ==254:#文件删除完成

251 print(data['status_msg'])252 print('删除前空间:',data['剩余空间'])253 pass

254 self.c.send(b'1')#发送到服务器,表示可以

255 data=self.get_response()#得到服务器的回复

256 if data["status_code"] ==255:#文件删除完成

257 print(data['status_msg'])258 print('删除后空间:',data['剩余空间'])259 return

260

261 #创建目录

262 def cmd_mkdir(self,cmd_list,**kwargs):263 mag_dict={264 "action":"mkdir",265 'filename':cmd_list[1]266 }267 self.c.send(json.dumps(mag_dict).encode('utf-8'))#发送文件信息

268 data=self.get_response()#得到服务器的回复

269 if data["status_code"] ==257:#目录已经存在

270 print(data['status_msg'])271 return

272 elif data["status_code"] ==256:#目录创建中

273 print(data['目录'])274 pass

275 self.c.send(b'1')#发送到服务器,表示可以

276 data=self.get_response()#得到服务器的回复

277 if data["status_code"] ==258:#目录创建中完成

278 print(data['status_msg'])279 return

280 pass

281

282 #删除目录

283 def cmd_rmdir(self,cmd_list,**kwargs):284 mag_dict={285 "action":"rmdir",286 'filename':cmd_list[1]287 }288 self.c.send(json.dumps(mag_dict).encode('utf-8'))#发送文件信息

289 data=self.get_response()#得到服务器的回复

290 if data["status_code"] ==256:#目录不存在

291 print(data['status_msg'])292 return

293 elif data["status_code"] ==260:#目录不为空

294 print(data['status_msg'])295 print(data['目录'])296 return

297 elif data["status_code"] ==257:#目录删除中

298 print(data['目录'])299 pass

300 self.c.send(b'1')#发送到服务器,表示可以

301 data=self.get_response()#得到服务器的回复

302 if data["status_code"] ==259:#目录删除完成

303 print(data['status_msg'])304 return

305 pass

306

307 #上传方法

308 def cmd_put(self,cmd_list,**kwargs):#上传方法

309 if len(cmd_list) > 1:310 filename=cmd_list[1]#取文件名

311 filename_dir=config.PUT_DIR+filename#拼接文件名路径

312

313 if os.path.isfile(filename_dir):#是否是一个文件

314 filesize=os.stat(filename_dir).st_size#获取文件大小

315 #执行行为 名字,大小,是否

316 mag_dict={317 "action":"put",318 'filename':filename,319 'size':filesize,320 'overridden':True,321 'md5':False322 }323 if self.cmd_md5_(cmd_list):#判断是否进行MD5

324 mag_dict['md5'] =True325 self.c.send(json.dumps(mag_dict).encode('utf-8'))#发送文件信息

326 data=self.get_response()#得到服务器的回复

327 if data["status_code"] ==250:#磁盘空间不足

328 print(data['status_msg'])329 print(mag_dict['size'])330 return

331 if data["status_code"] ==249:#磁盘空间足够

332 print(data['status_msg'])333 print('剩余空间',data['剩余空间'])334 self.c.send(b'1')#发送到服务器,表示可以上传文件了

335 data=self.get_response()#得到服务器的回复

336 if data["status_code"] ==230:#断点续传

337 print(data['status_msg'])338 print(data['文件大小'])339 self.rat=data['文件大小']#文件指针位置

340 pass

341 elif data["status_code"] ==231:#非断点续传

342 print(data['status_msg'])343 self.rat=0#文件指针位置

344 pass

345 f=open(filename_dir,'rb')#打开文件

346 f.seek(self.rat)#移动到位置

347 print(mag_dict['md5'])348 self.c.send(b'1')#发送到服务器,表示可以上传文件了

349 if mag_dict['md5']==True:350 md5_obj = hashlib.md5()#定义MD5

351 progress = self.show_pr(mag_dict['size']) #进度条 传入文件大小

352 progress.__next__()353 while self.rat<354 line="f.read(1024)355" self.c.send try:357 progress.send>

358 exceptStopIteration as e:359 print("100%")360 break

361 md5_obj.update(line)#计算MD5

362

363 else:364 print(filename,'发送完成!')365 f.close()366 md5_val =md5_obj.hexdigest()367 md5_from_server = self.get_response()#服务端的MD5

368 if md5_from_server['status_code'] == 248:369 if md5_from_server['md5'] ==md5_val:370 print("%s 文件一致性校验成功!" %filename)371 return

372 else:373 progress = self.show_pr(mag_dict['size']) #进度条 传入文件大小

374 progress.__next__()375 #for line in f:

376 while self.rat<377 line="f.read(1024)378" self.c.send try:380 progress.send>

381 exceptStopIteration as e:382 print("100%")383 break

384 #print(line)

385 else:386 print(filename,'发送完成!')387 f.close()388 return

389 else:390 print(filename,'文件不存在!')391

392 #下载方法

393 def cmd_get(self,cmd_list,**kwargs):#下载方法

394 #cmd_split= args[0].split()#指令解析

395 #if len(cmd_list) == 1:

396 #print("没有输入文件名.")

397 #return

398 #down_filename = cmd_list[1].split('/')[-1]#文件名

399 down_filename=cmd_list[1]#取文件名

400 file_path='%s/%s'%(config.GET_DIR,down_filename)#拼接文件路径 用户down目录

401 if os.path.isfile(file_path):#文件是否存

402 filesize=os.stat(file_path).st_size#获取文件大小

403 name_down=True404 else:405 filesize=0406 name_down=False407 mag_dict={408 "action":"get",409 'filename':cmd_list[1],410 'name_down':name_down,411 'size':filesize412 }413 if self.cmd_md5_(cmd_list):#判断是否进行MD5

414 mag_dict['md5'] =True415 self.c.send(json.dumps(mag_dict).encode())#发送

416 self.c.send(b'1')#发送到服务器,防粘包

417

418 response = self.get_response()#服务器返回文件 的信息

419 if response["status_code"] ==247:#如文件存在

420 if name_down==True and response['file_size']==filesize:421 print('文件已经下载完成')422 self.c.send(b'2')423 return

424 self.c.send(b'1')#发送到服务器,表示可以接收文件了

425 #if name_down:

426 received_size = filesize#当前接收的数据大小

427 #else:

428 #received_size = 0#当前接收的数据大小

429

430 file_obj = open(file_path,"ab")#打开文件

431 ifself.cmd_md5_(cmd_list):432 md5_obj =hashlib.md5()433 progress = self.show_pr(response['file_size']) #进度条 传入文件大小

434 progress.__next__()435 while received_size< response['file_size']:436 if response['file_size'] - received_size>1024:#表示接收不止一次

437 size=1024

438 else:#最后一次

439 size=response['file_size'] -received_size440 #print('最后一个大小',size)

441 data= self.c.recv(size)#接收数据

442

443 try:444 progress.send(len(data))#传入当前数据大小

445 exceptStopIteration as e:446 print("100%")447 received_size+=len(data)#接收数据大小累加

448 file_obj.write(data)#写入文件

449 md5_obj.update(data)#进行MD5验证

450 else:451 print("下载完成".center(60,'-'))452 file_obj.close()453 md5_val = md5_obj.hexdigest()#获取MD5

454 #print(md5_val)

455 md5_from_server = self.get_response()#服务端的MD5

456 #print(md5_from_server['md5'])

457 if md5_from_server['status_code'] == 248:458 if md5_from_server['md5'] ==md5_val:459 print("%s 文件一致性校验成功!" %down_filename)460 pass

461 else:462 progress = self.show_pr(response['file_size']) #进度条 传入文件大小

463 progress.__next__()464 while received_size< response['file_size']:465 if response['file_size'] - received_size>1024:#表示接收不止一次

466 size=1024

467 else:#最后一次

468 size=response['file_size'] -received_size469 #print('最后一个大小',size)

470 data= self.c.recv(size)#接收数据

471

472 try:473 progress.send(len(data))#传入当前数据大小

474 exceptStopIteration as e:475 print("100%")476 received_size+=len(data)#接收数据大小累加

477 file_obj.write(data)#写入文件

478 pass

479

480 else:481 print("下载完成".center(60,'-'))482 file_obj.close()483 pass

484 self.c.send(b'1')#发送到服务器,表示可以接收文件了

485

486 if __name__=='__main__':487

488 c=FTPClient()489 c.inter()

377>354>192>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值