用python实现FTP客户端

暑假做的唯一一个有意义的项目吧,其实原理很简单。主要是其中学了不少Ubuntu的东西。今天正好没事,整理一下,以便后面查阅。

首先推荐一个好用的FTP管理程序--IIS7服务器管理工具:

“IIS7服务器管理工具是一款windows全系、Linux系统下链接并操控VPS、VNC、FTP等远程服务器、云服务器。
界面简单明了,操作易上手,功能强大,支持批量导入服务器,并批量打开,多窗口化管理,除此之外,加载本地硬盘、硬盘映射、加载服务器的声音,远程声卡读取等,完全实现各类场景使用,对于FTP链接界面,朋友FTP定时上传,定时下载(也可以说定时上传下载 定时备份),对于经常使用FTP的小伙伴来说,非常适用。
工具支持自动更新,压缩包只有7.62M,方便简洁,一步到位。“

下载地址

使用说明:

 

 

 

 

一、 程序说明。

ftp.py程序说明。

 

程序功能:这个程序主要由三个功能。1.浏览ftp服务器目录。2.随机下载一个文件。3.随机下载多个文件。

1.       浏览ftp服务器目录。

这个功能主要是在登入进ftp服务器后,生成一个随机数,根据随机数,进行判断往哪个目录下索引。如果是根目录,只会向下索引。如果是底层目录,只会向上索引。

2.       随机下载一个文件。

这个功能主要是在登入进ftp服务器后,生成一个随机数,根据随机数,随机下载一个文件。需要注意的是,生成随机数之前,要进行判断。如果没有要下载的文件,就要切换目录,进行下载。

3.       随机多个文件下载

这个功能主要是在登入ftp服务器后,随机下载多个文件。实现原理为,首先进入一个目录下,判断是否有文件下载,如果有文件下载,则下载多个文件,如果没有,则改变目录。完成后改变目录。

 

所需参数:“ip,port,username,passwd,usermodel”。传入参数由一个字符串组成。用逗号进行分割。

 

所需环境:需要搭建好ftp服务器。以及有python环境的系统上运行。

 

注意事项:

1.       下载路径默认为”/home/”。如果程序出错提示为“不能写入”,需要对文件权限进行提升。

2.       在实现用户模式时,程序已经默认多次执行。即每次运行程序时,就会随机多次(至少一次,最多5次)执行,用来模拟用户行为。

3.       ftp服务器搭建详见ftp服务器搭建教程。

 

 

  1 #!/usr/bin/env Python3
  2 # -*- encoding:utf-8 -*-
  3 from ftplib import FTP
  4 from random import randint
  5 import time
  6 import sys
  7 
  8 
  9 
 10 
 11 def ftpconnect(ip, port,  username, passwd):
 12     ftp = FTP()
 13     #ftp.set_debuglevel(2)  # 打开调试级别2,显示详细信息
 14     ftp.connect(ip, port)  # 连接的ftp服务器ip和port
 15     ftp.login(username, passwd)  # 连接的用户名和密码
 16     print(ftp.getwelcome())  # 打印出欢迎信息。
 17     return ftp
 18 
 19 def showdownloadfile(ftp):
 20     #print("当前目录下的文件:文件夹名字:"+ftp.pwd())
 21     mu_dir = gettable(ftp)
 22     #print("当前文件夹: "+ftp.pwd()+"  可供下载的文件:")
 23     behind_name = []
 24     for name in mu_dir:
 25         if mu_dir[name] == "文件":
 26             behind_name.append(name)
 27             #print(name)
 28     return behind_name
 29 
 30 def showfolderfile(ftp):
 31     #print("当前目录下的文件:文件夹名字:"+ftp.pwd())
 32     mu_dir = gettable(ftp)
 33     #print("当前文件夹:  "+ftp.pwd()+"   可供索引的文件夹:")
 34     folder_name = []
 35     for name in mu_dir:
 36         if mu_dir[name] == "文件夹":
 37             folder_name.append(name)
 38             #print(name)
 39     return folder_name
 40 
 41 def randomdownload(ftp, localpath, str):
 42     # 当前目录下可供下载的文件名字
 43     behind_name = showdownloadfile(ftp)
 44     #print("当前文件夹: "+ftp.pwd()+"  可供下载的文件:")
 45     #print(behind_name)
 46     # 随机数
 47     while len(behind_name) == 0:  # 说明没有可以下载的文件
 48         # 切换文件夹
 49         changetable(ftp,str)
 50         behind_name = showdownloadfile(ftp)
 51     file_random = randint(0, len(behind_name)-1)
 52     filename = behind_name[file_random]
 53     print("当前目录为:  "+ftp.pwd())
 54     print("下载文件为 "+filename)
 55     # 设置下载数据
 56     bufsize = 1024  # 设置缓冲区大小
 57     new_path = localpath+filename  # 设置下载路径
 58     
 59     fp = open(new_path, 'wb')
 60     ftp.retrbinary('RETR ' + filename, fp.write, bufsize)  # 下载FTP文件。FTP命令 RETR filename
 61     fp.close()
 62     print(filename+' 下载成功')
 63 
 64 
 65 def downloadfiles(ftp, localpath, str):  # 根目录不能继续向下,没有目录不能索引(这个可以自动实现)。
 66     # 在当前目录下随机下载几个文件
 67     behind_name = showdownloadfile(ftp)
 68     #folder_name = showfolderfile(ftp)
 69     while len(behind_name) == 0:  # 说明没有可以下载的文件
 70         # 切换文件夹
 71         changetable(ftp, str)
 72         behind_name = showdownloadfile(ftp)
 73 
 74     randomb = randint(0, len(behind_name)-1)
 75     while randomb:  # 在这个文件夹下随机下载几个
 76         randomdownload(ftp, localpath, str)
 77         randomb -= 1
 78     # 切换目录下载(可能向下或者向上)
 79     #viewtable(ftp)
 80 
 81 
 82 
 83 
 84 def gettable(ftp):  # 获取目录结构
 85     dir_del = []
 86 
 87     table_dir = {}
 88     ftp.dir('.', dir_del.append)  # 根据文件目录,进行拆分。
 89     for name in dir_del:
 90         strname = str(name)
 91         temp = strname.split(' ')
 92         attrname = []
 93         for j in range(0,len(temp)):
 94             if temp[j] != '':
 95                 attrname.append(temp[j])
 96         m = ' '.join(attrname[8:])
 97         if strname.startswith('d'):
 98             #print('文件夹:', m)
 99             table_dir[m] = '文件夹'
100         else:
101             #print('文件:', m)
102             table_dir[m] = '文件'
103     return table_dir  # 字典,key值是文件名,value是类型
104 
105 def viewtable(ftp,str):
106     #gettable(ftp)  # 获取当前目录
107     changtimes = randint(1, 4)  # 随机切换几次目录
108     while changtimes:
109         changtimes -= 1
110         folder_name = showfolderfile(ftp)
111         print("当前目录下为:  "+ftp.pwd())
112         print("目录结构:")
113         print(gettable(ftp))
114         if len(folder_name) > 0:  # 有可供索引的文件夹
115             if ftp.pwd() == str:  # 为根目录,只能向下索引
116                 print("向下索引后目录为:")
117                 randomf = randint(0, len(folder_name)-1)
118                 path = ftp.pwd()+folder_name[randomf]
119                 ftp.cwd(path)
120                 print("当前目录下为:  "+ftp.pwd())
121                 print("目录结构:")
122                 print(gettable(ftp))
123 
124             else:  # 向上向下索引都可以
125                 downorup = randint(0, 1)
126                 if downorup:  # 向下索引
127                     print("向下索引后目录为:")
128                     randomf = randint(0, len(folder_name)-1)
129                     path = ftp.pwd()+folder_name[randomf]
130                     ftp.cwd(path)
131                     print("当前目录下为:  "+ftp.pwd())
132                     print("目录结构:")
133                     print(gettable(ftp))
134 
135                 else:
136                     print("向上索引后,目录为:")
137                     path = '../'
138                     ftp.cwd(path)
139                     print("当前目录下为:  "+ftp.pwd())
140                     print("目录结构:")
141                     print(gettable(ftp))
142         else:  # 没有可供索引的文件夹,可以向上索引。
143             if ftp.pwd() != str:
144                 print("向上索引后,目录为:")
145                 path = '../'
146                 ftp.cwd(path)
147                 print("当前目录下为:  "+ftp.pwd())
148                 print("目录结构:")
149                 print(gettable(ftp))
150 
151 def changetable(ftp,str):
152     folder_name = showfolderfile(ftp)
153     if len(folder_name) > 0:  # 有可供索引的文件夹
154         if ftp.pwd() == str:  # 为根目录,只能向下索引
155             randomf = randint(0, len(folder_name)-1)
156             path = ftp.pwd()+folder_name[randomf]
157             ftp.cwd(path)
158 
159         else:  # 向上向下索引都可以
160             downorup = randint(0, 1)
161             if downorup:  # 向下索引
162                 randomf = randint(0, len(folder_name)-1)
163                 path = ftp.pwd()+folder_name[randomf]
164                 ftp.cwd(path)
165 
166             else:
167                 path = '../'
168                 ftp.cwd(path)
169     else:  # 没有可供索引的文件夹,可以向上索引。
170         if ftp.pwd() != str:
171             path = '../'
172             ftp.cwd(path)
173 def ftpmain(ip, port, username, passwd, localpath, userModel):
174     # 1.连接到ftp服务器
175     ftp = ftpconnect(ip, port,  username, passwd)
176     # 2.开始交互
177     str = ftp.pwd()
178     #print(str)
179     # usermodel 也可以是一个列表序列,让一个用户,执行多个操作。
180     cmdtimes = randint(1, 5)  # 这随机多次执行用户模式。
181     #downloadtimes = 3  # 多个文件多次下载
182     while cmdtimes:
183         cmdtimes -= 1
184         if userModel == 1:  # 浏览模式
185             viewtable(ftp, str)
186             changetable(ftp, str)
187             continue
188         if userModel == 2:  # 下载模式
189             randomdownload(ftp, localpath, str)
190             changetable(ftp, str)
191             continue
192         if userModel == 3:  # 同时下载多个文件模式
193             #while downloadtimes:
194             downloadfiles(ftp, localpath, str)
195             changetable(ftp, str)
196             #downloadtimes -= 1
197             continue
198         else:  # 错误处理机制
199             print('无法识别传递的模式编号:')
200             break
201 
202     ftp.quit()
203 
204 
205 if __name__ == "__main__":
206     agrvlist = sys.argv[1].split(',')
207     ip = agrvlist[0]
208     port = int(agrvlist[1])
209     username = agrvlist[2]
210     passwd = agrvlist[3]
211     usermodel = int(agrvlist[4])
212     ftpmain(ip, port, username, passwd, "/home/username/", usermodel)
View Code

 

从程序中我们可以看出,其实还是很简单的。主要是引入ftplib库。用pip就可以。

下面简单说一下,我在编程中主要遇到的问题:

1.区分ftp服务器里面的文件夹和文件。

这里是解决的方法:

 1 def gettable(ftp):  # 获取目录结构
 2     dir_del = []
 3 
 4     table_dir = {}
 5     ftp.dir('.', dir_del.append)  # 根据文件目录,进行拆分。
 6     for name in dir_del:
 7         strname = str(name)
 8         temp = strname.split(' ')
 9         attrname = []
10         for j in range(0,len(temp)):
11             if temp[j] != '':
12                 attrname.append(temp[j])
13         m = ' '.join(attrname[8:])
14         if strname.startswith('d'):
15             #print('文件夹:', m)
16             table_dir[m] = '文件夹'
17         else:
18             #print('文件:', m)
19             table_dir[m] = '文件'
20     return table_dir  # 字典,key值是文件名,value是类型
View Code

主要是先获取服务器文件夹里面的详细信息,通过分析,利用python的数据结构来区分。

下面是我的分析过程:

这是ftp服务器主目录下,通过ftp.dir(),然后输出结果为:

['drwxrwxrwx    2 0        0            4096 Jul 04 21:17 hello', '-rw-------    1 1001     131             3 Jul 05 10:20 test', '-rwxrwxrwx    1 1000     1000      2840284 Apr 20  2016 test.ogg']

通过查阅发现:hello是文件夹,test和test.ogg是文件。

然后进一步查分,最后通过'd'来区分。

strname.startswith('d')

2.获取外部输入

这个程序不是直接编译通过的,而是要传递外部参数。利用sys库进行操作。通过控制台运行函数。

1 if __name__ == "__main__":
2     agrvlist = sys.argv[1].split(',')
3     ip = agrvlist[0]
4     port = int(agrvlist[1])
5     username = agrvlist[2]
6     passwd = agrvlist[3]
7     usermodel = int(agrvlist[4])
View Code

由于 外部参数都是以字符串形式传入,所以要进行格式转换操作。

3.限制下载速度。

这个功能在程序中没有实现。后来通过阅读关于网络的书籍,关于tcp的过程,其实是可以通过设置缓冲区的大小来模拟延迟的。当然这个下载速度服务器是由主导权的。

这个项目主要学到的东西在ftp服务器搭建中,放到下个随笔中。

 

posted @ 2018-08-27 20:12  昔时  阅读(4612)  评论(0编辑  收藏  举报