用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服務器搭建中,放到下個隨筆中。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM