该文档为用python3实现ftp上传下载等功能。

 1 import optparse
 2 import socket
 3 import json,os
 4 import shelve
 5 
 6 class FtpClient(object):
 7     """ftp客户端"""
 8     MSG_SIZE = 1024  # 消息最长1024
 9 
10     def __init__(self):
11         self.username = None
12         self.terminal_display = None
13         self.shelve_obj = shelve.open(".luffy_db")
14         self.current_dir = None
15 
16         parser = optparse.OptionParser()#创建parser这个对象,optparse这个模块是个类
17         parser.add_option("-s","--server", dest="server", help="ftp server ip_addr")
18         parser.add_option("-P","--port",type="int", dest="port", help="ftp server port")
19         parser.add_option("-u","--username", dest="username", help="username info")
20         parser.add_option("-p","--password", dest="password", help="password info")
21         self.options , self.args = parser.parse_args()
22 
23         #print(self.options,self.args,type(self.options),self.options.server)
24         self.argv_verification()#调用检查参数合法性函数
25 
26         self.make_connection()#调用建立socket连接函数

上面这段首先创建一个类。该客户端代码均在这个类中实现。

定义一个接收值的变量,然后定义初始化函数,定义几个静态属性,这几个属性有些是后面函数需要的,所以提前定义。

之后用OptionParser这个函数生成一个命令行声明。这个函数具体相关可以从网络中查到。

再之后调用两个函数,一个是检查参数合法性的,另一个是建立socket连接。

 

 1     def argv_verification(self):
 2         """检查参数合法性"""
 3         if not self.options.server or not self.options.port:
 4             #如果options的server参数或port参数不为真则exit()关闭并打印括号内内容。
 5             exit("Error: must supply server and port parameters")
 6 
 7 
 8     def make_connection(self):
 9         """建立socket链接"""
10         self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
11         self.sock.connect((self.options.server,self.options.port))
12 
13     def get_response(self):#接收返回值
14         """获取服务器端返回"""
15         data = self.sock.recv(self.MSG_SIZE)#接收1024个
16         return json.loads(data.decode())#返回decode之后内容

上面代码为三个函数,分别是检查合法性、创建连接、接收返回值。

 1     def auth(self):
 2         """用户认证"""
 3         count = 0
 4         while count < 3:#输入最多3次
 5             username = input("username:").strip()
 6             if not username:continue#如果输入不为真则继续
 7             password = input("password:").strip()
 8 
 9             cmd = {
10                 'action_type':'auth',#action_type定义功能关键词,将关键词传入值
11                 'username':username,#用户名
12                 'password':password,#密码
13             }
14             #定义一个字典,该字典将为以后客户端与服务端通讯作为模板。
15             self.sock.send(json.dumps(cmd).encode("utf-8"))#将字典序列化然后encode,发送
16             response = self.get_response()#调用get_response函数,并赋值。该函数获取服务器端返回内容,并反序列化
17             print("response:",response)#打印得到的内容
18             if response.get('status_code') == 200:#pass auth#如果得到的内容是状态码200
19                 self.username = username
20                 # 定义一个数据属性,将__init__里的None赋值掉,为了以后调用方便
21                 self.terminal_display = "[%s]>>:" % self.username#将用户名赋值给显示
22                 self.current_dir = "\\"#设置当前目录路径,将init函数重写
23                 return True
24             else:
25                 print(response.get("status_msg"))#如果验证不成功打印状态码
26             count += 1

auth函数主要负责登录认证功能。注释写的蛮详细了,我就不赘述了。

 1     def unfinished_file_check(self):
 2         """检查shelve db ,把为正常传完的文件列表打印,按用户的指令决定是否重传"""
 3         if list(self.shelve_obj.keys()):#如果shelve列表为真
 4             print("-------Unfinished file list -------------")
 5             for index,abs_file in enumerate(self.shelve_obj.keys()):
 6                 #enumerate函数将一个可迭代的容器列出它的索引
 7                 received_file_size = os.path.getsize(self.shelve_obj[abs_file][1])
 8                 #接收到的大小=getsize大小
 9                 print("%s. %s    %s    %s   %s" %(index,abs_file,
10                                                   self.shelve_obj[abs_file][0],
11                                                   received_file_size,
12                                                   received_file_size/self.shelve_obj[abs_file][0]*100
13                                                   ))
14 
15             while True:
16                 choice = input("[select file index to re-download]").strip()
17                 if not choice:continue
18                 if choice == 'back':break
19                 if choice.isdigit():
20                     choice = int(choice)
21                     if choice >= 0 and choice <= index:
22                         selected_file = list(self.shelve_obj.keys())[choice]
23                         already_received_size = os.path.getsize(self.shelve_obj[selected_file][1])
24 
25                         print("tell server to resend file ", selected_file)
26                         #abs_filename + size +received_size
27                         self.send_msg('re_get', file_size=self.shelve_obj[selected_file][0],
28                                       received_size=already_received_size,
29                                       abs_filename=selected_file)
30 
31                         response = self.get_response()
32                         if response.get('status_code') == 401:#"File exist ,ready to re-send !",
33                             local_filename = self.shelve_obj[selected_file][1]
34 
35 
36 
37                             f = open(local_filename,'ab')
38                             total_size = self.shelve_obj[selected_file][0]
39                             recv_size = already_received_size
40                             current_percent = int(recv_size /total_size *100)
41                             progress_generator = self.progress_bar(total_size,current_percent,current_percent)
42                             progress_generator.__next__()
43                             while recv_size < total_size:
44                                 if total_size - recv_size < 8192:  # last recv
45                                     data = self.sock.recv(total_size - recv_size)
46                                 else:
47                                     data = self.sock.recv(8192)
48                                 recv_size += len(data)
49                                 f.write(data)
50                                 progress_generator.send(recv_size)
51                                 #progress_generator.send(received_size)
52                                 #print(recv_size,total_size)
53                             else:
54                                 print("file re-get done")
55                         else:
56                             print(response.get("status_msg"))
断点续传

相关文章: