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

1 importoptparse2 importsocket3 importjson,os4 importshelve5

6 classFtpClient(object):7 """ftp客户端"""

8 MSG_SIZE = 1024 #消息最长1024

9

10 def __init__(self):11 self.username =None12 self.terminal_display =None13 self.shelve_obj = shelve.open(".luffy_db")14 self.current_dir =None15

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 defargv_verification(self):2 """检查参数合法性"""

3 if not self.options.server or notself.options.port:4 #如果options的server参数或port参数不为真则exit()关闭并打印括号内内容。

5 exit("Error: must supply server and port parameters")6

7

8 defmake_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 defauth(self):2 """用户认证"""

3 count =04 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 =username20 #定义一个数据属性,将__init__里的None赋值掉,为了以后调用方便

21 self.terminal_display = "[%s]>>:" % self.username#将用户名赋值给显示

22 self.current_dir = "\\"#设置当前目录路径,将init函数重写

23 returnTrue24 else:25 print(response.get("status_msg"))#如果验证不成功打印状态码

26 count += 1

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

1 defunfinished_file_check(self):2 """检查shelve db ,把为正常传完的文件列表打印,按用户的指令决定是否重传"""

3 if list(self.shelve_obj.keys()):#如果shelve列表为真

4 print("-------Unfinished file list -------------")5 for index,abs_file inenumerate(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 whileTrue:16 choice = input("[select file index to re-download]").strip()17 if not choice:continue

18 if choice == 'back':break

19 ifchoice.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_size40 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 <44 if total_size recv_size 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"))

断点续传

该函数为断点续传功能,改天写注释。该函数大量使用shelve。

1 definteractive(self):2 """处理与Ftpserver的所有交互"""

3 ifself.auth():4 self.unfinished_file_check()5

6 whileTrue:7 user_input = input(self.terminal_display).strip()#输入的时候显示名字后来变成路径

8 if not user_input:continue

9

10 cmd_list = user_input.split()#登录之后,将输入的内容转化成列表

11 if hasattr(self,"_%s"%cmd_list[0]):#判断输入的内容列表索引0 这个类里是否有这个方法

12 func = getattr(self,"_%s"%cmd_list[0])#获取这个方法。

13 func(cmd_list[1:])#执行这个函数,将input后面所有的内容作为列表传进去

14 #get fil1 --md5

interactive函数负责与服务端的交互。首先调用登陆验证,然后就是下载未完成文件的检查,之后是负责交互。

1 def parameter_check(self,args,min_args=None,max_args=None,exact_args=None):2 """参数个数合法性检查3 # args这个传进来的参数是一个列表,min_args默认值看函数的定义。4 下面的判断如果符合一条则报错,没有符合的则正常。"""

5 ifmin_args:6 if len(args) <7 print provide at least parameters but received. returnfalse9 ifmax_args:10 if len>max_args:11 print("need at most %s parameters but %s received." %(max_args,len(args)))12 returnFalse137>

14 ifexact_args:15 if len(args) !=exact_args:16 print("need exactly %s parameters but %s received." %(exact_args, len(args)))17 returnFalse18

19 return True

parameter_check

parameter_check是参数的合法性检查,检查输入内容命令+参数后面的参数格式。

def send_msg(self,action_type,**kwargs ):#action_type传进来的是get,**是文件名

"""打包消息并发送到远程"""msg_data={'action_type': action_type,'fill':''}

msg_data.update(kwargs)#将文件名这个字典作为key传到字典里,update本质是两个字典合并成一个字典。

bytes_msg= json.dumps(msg_data).encode()#将字典序列化,目的是为了将字典转化为字符串,好算长度

if self.MSG_SIZE > len(bytes_msg):#如果1024>这个序列化后的字典

msg_data['fill'] = msg_data['fill'].zfill( self.MSG_SIZE -len(bytes_msg))

bytes_msg= json.dumps(msg_data).encode()#将调整大小后的字典序列化

self.sock.send(bytes_msg)#发送

send_msg负责具体向服务端发送消息的工作。

1 def_ls(self,cmd_args):2 """

3 display current dir's file list4 :param cmd_args:5 :return:6 """

7 self.send_msg(action_type='ls')#发送消息,将ls命令通过字典发出去

8 response = self.get_response() #1024#收消息

9 print('ls recv',response)#打印

10 if response.get('status_code') == 302:#取出收到的字典中的状态码,判断是否为302

11 cmd_result_size = response.get('cmd_result_size')#收到信息获取返回值长度

12 print(cmd_result_size)#打印长度看一下

13 received_size = 0#定义一个初始值

14 cmd_result = b''#定义一个初始值

15 while received_size < cmd_result_size:#当收入大小小于实际大小

16 if cmd_result_size - received_size < 8192:#last receive#实际大小-收入大小小于8192

17 data = self.sock.recv( cmd_result_size - received_size)#继续收入上面这个差值

18 else:19 data = self.sock.recv(8192)#入过差值大过8192 那么索性直接收8192

20 cmd_result += data#收入的文件+=recv的内容

21 received_size += len(data)#收入的长度+=recv的长度

22 else:23 print(cmd_result.decode("gbk"))#当收入大小不小于实际大小,那么直接打印

_ls函数是负责ls命令的功能,调用send_msg发送命令并调用get_response接收返回值,期间解决了粘包的问题。

1 def_cd(self,cmd_args):2 """change to target dir"""

3 if self.parameter_check(cmd_args, exact_args=1):#参数合法性校验

4 target_dir = cmd_args[0] #赋值

5 self.send_msg('cd',target_dir=target_dir) #发送消息

6 response = self.get_response()#接收消息

7 print(response)#打印

8 if response.get("status_code") == 350:#dir changed

9 self.terminal_display = "[/%s]" % response.get('current_dir')#修改输入端显示

10 self.current_dir = response.get('current_dir')#将current_dir赋值

_cd函数负责cd命令的处理。

1 def_get(self,cmd_args):2 """download file from ftp server3 1.拿到文件名4 2.发送到远程5 3.等待服务器返回消息6 3.1 如果文件存在, 拿到文件大小7 3.1.1 循环接收8 3.2 文件如果不存在9 print status_msg10

11 """

12 if self.parameter_check(cmd_args,min_args=1):13 #cmd_args这个传进来的参数是一个列表,min_args默认是1,执行判断参数合法性函数,将列表传进去

14 filename = cmd_args[0]#将参数0赋值为文件名

15 self.send_msg(action_type='get',filename=filename)#运行发送函数,将action为get等内容字典传值。

16 response = self.get_response()#接收返回值

17 if response.get('status_code') == 301:#file exist ,ready to receive

18 file_size = response.get('file_size')#取返回值里的文件大小

19 received_size = 0#先定义为0

20

21 progress_generator =self.progress_bar(file_size)22 progress_generator.__next__()23

24 #save to shelve db

25 file_abs_path =os.path.join(self.current_dir,filename)26 self.shelve_obj[file_abs_path] = [file_size,"%s.download" %filename]27

28 f = open("%s.download" %filename,"wb")#打开一个空文件

29 while received_size < file_size:#如果收到的大小小于文件大小

30 if file_size - received_size < 8192:#last recv如果文件大小-收到的大小之后小于8192

31 data = self.sock.recv( file_size - received_size )#继续接收文件大小没有收到的数量值

32 else:33 data = self.sock.recv(8192)#如果大于8192则直接接收8192

34 received_size += len(data)#没接收一次数据,将数据大小增加

35 f.write(data)36 progress_generator.send(received_size)#打印文件大小和接收大小

37

38 #print(received_size,file_size)

39 else:40 print('\n')41 print("---file [%s] recv done,received size [%s]----"%( filename,file_size))42 delself.shelve_obj[file_abs_path]43 f.close()#如果接收到的大小不小于文件大小,等于文件大小,那就传完了

44 os.rename("%s.download"%filename,filename)45

46 else:47 print(response.get('status_msg'))#打印状态码,文件不存在

_get函数负责下载相关,同样需处理粘包工作。

1 def progress_bar(self,total_size,current_percent=0,last_percent=0):2

3 #current_percent = 0

4 #last_percent = 0

5 #received_size = 0

6 whileTrue:7 received_size = yieldcurrent_percent8 current_percent = int(received_size / total_size *100)9

10 if current_percent >last_percent:11 print("#" * int(current_percent / 2) + "{percent}%".format(percent=current_percent), end='\r',12 flush=True)13 last_percent = current_percent #把本次循环的percent赋值给last

progress_bar。进度条功能。

1 def_put(self,cmd_args):2 """上传本地文件到服务器3 1. 确保本地文件存在4 2. 拿到文件名+大小,放到消息头里发给远程5 3. 打开文件,发送内容6 """

7 if self.parameter_check(cmd_args, exact_args=1):#参数合法性检查

8 local_file = cmd_args[0]#取文件名

9 if os.path.isfile(local_file):#判断文件存在

10 total_size = os.path.getsize(local_file)#取文件大小

11 self.send_msg('put',file_size=total_size,filename=local_file)#发送

12 f = open(local_file,'rb')13 uploaded_size =014 #last_percent = 0

15

16 progress_generator = self.progress_bar(total_size)#进度条

17 progress_generator.__next__()#next一下

18 for line inf:19 self.sock.send(line)20 uploaded_size +=len(line)21 #current_percent = int(uploaded_size / total_size * 100)

22 #if current_percent > last_percent:

23 #print("#"* int(current_percent/2) + "{percent}%".format(percent=current_percent),end='\r',flush=True)

24 #last_percent = current_percent #把本次循环的percent赋值给last

25 progress_generator.send(uploaded_size)26

27 else:28 print('\n')29 print('file upload done'.center(50,'-'))30 f.close()

上传功能的函数。

1 if __name__ == "__main__":2 client =FtpClient()3 client.interactive() #交互

执行该py文件需使用cmd,格式为 filename.py -s IP -P port执行。

44>

python实现ftp_python实现ftp(客户端)相关推荐

  1. python编写ftp客户端_用Python写FTP客户端程序

    0 前言: ftp客户端相信大家都用过,那么我们为什么还要用Python写ftp客户端呢? 我想有两个原因: 一是写出更好的ftp客户端应用程序,方便大家使用: 二是定制一些特殊服务,例如每天定时下载 ...

  2. python ftplib_python:使用ftplib编写FTP客户端

    Python中的ftplib模块 Python中默认安装的ftplib模块定义了FTP类,其中函数有限,可用来实现简单的ftp客户端,用于上传或下载文件 FTP的工作流程及基本操作可参考协议RFC95 ...

  3. python编写ftp客户端_python实现ftp客户端示例分享

    代码如下: #!/usr/bin/python #coding:utf-8 #write:JACK #info:ftp example import ftplib, socket, os from t ...

  4. python生成简单的FTP弱口令扫描

    2019独角兽企业重金招聘Python工程师标准>>> 前言 Ftp这个类实现了Ftp客户端的大多数功能,比如连接Ftp服务器.查看服务器中的文件.上传.下载文件等功能,Ftp匿名扫 ...

  5. 18. 编写FTP客户端程序

    在实际应用中可能经常访问FTP服务器来上传或下载文件,Python也可以替我们做这些. [示例 1]下面请看一个例子(ftpclient). 运行的结果如下: FTP客户端程序的编写还可以参照官方文档 ...

  6. 7个免费的Linux FTP客户端工具

    在Dropbox.YouSendIt.idrive以及许多这样云存储和共享工具的帮助下,我们在互联网上发送和共享大型文件变得容易起来.所有这些网站都可以帮助你在互联网上传送文件,但如果你要分享庞大的数 ...

  7. 计算机网络 简单FTP客户端软件的实现

    一.原理概述 1.1 FTP原理概述 文件传送协议FTP(File Transfer Protocol)是TCP/IP体系的一个重要协议,它采用Internet标准文件传输协议FTP的用户界面,向用户 ...

  8. Linux安装FTP及使用python上传下载ftp

    参考 https://www.cnblogs.com/mingforyou/p/4103022.html 一.安装及配置 1.直接使用yum安装 yum -y install vsftpd 2.配置文 ...

  9. python:poplib --- POP3 协议客户端

    python:poplib --- POP3 协议客户端 简介 POP3 对象 POP3 示例 简介 本模块定义了一个 POP3 类,该类封装了到 POP3 服务器的连接过程,并实现了 RFC 193 ...

  10. 网络编程--ftp客户端的实现(c#版)

    .net2.0对ftp有了一个很好的封装,但是确容易让人忽略ftp的真正内部实现,下面是我实现的ftp客户端的功能,其主要步骤是这样的: 1.创建一个FtpWebRequest对象,指向ftp服务器的 ...

最新文章

  1. 算法设计与分析男女匹配问题C语言,C语言解决新郎和新娘配对问题代码解析
  2. linux服务器黑屏_xshell连接Linux系统(小红帽7.3)服务器,导致服务器黑屏
  3. 散谈游戏保护那点事~就从_TP开始入手吧
  4. Linux 中统计一个进程的线程数
  5. 电脑音响怎么插_BMW宝马5系G38改原厂全套哈曼卡顿音响+无钥匙进入,厚街宝马原厂改装中心...
  6. Matlab R2016a破解安装教程
  7. 使用libevhtp搭建HTTPS SERVER(单向验证身份)
  8. mysql查询语句内连接、左连接、右连接以及全连接查询
  9. 加密与解密 调试篇(二) Windows调试器实现(一)
  10. 中国智能燃气表行业发展态势分析及投资风险评估报告2022-2028年版
  11. 单片机实验六 动态数码管实验
  12. c语言循环语循环控制,C语言.控制语循环语句.ppt
  13. java sequencer_java sequencer播放列表
  14. 1.0django入门01
  15. 【Matlab】RGB, HSV 颜色空间绘制
  16. 沈阳师范大学大一上册C语言PTA题目集以及答案(第三章 循环结构程序设计 编程题篇)
  17. standupTimer项目中的布局容器
  18. 如何使用pip安装causalml
  19. 数码相机短片合并及压缩工具(数码短片伴侣)
  20. 文件IO中read()函数读取输出字符串有乱码

热门文章

  1. 小米手机全黑屏9008救砖
  2. 正则判断手机号地区_匹配中国大陆所有手机号正则表达式
  3. Redis 如何使用 Bitmap
  4. c语言小车路径规划算法,自动驾驶汽车四种常用的路径规划算法解析
  5. 热传导问题的matlab计算,热传导问题的MATLAB数值计算
  6. u大师u盘自定义ISO/IMG文件装机教程
  7. LabelImg操作手册
  8. sklearn做文本聚类分析
  9. 问题解决之——未知usb设备设备描述符请求失败(Jlink驱动)
  10. 2022年最新全国各省五级行政区划代码及mysql数据库代码(省市区县乡镇村)