1、FTP服務的主動模式和被動模式:
主動模式工作過程:
- 客戶端以隨機非特權(quán)端口N凌蔬,就是大于1024的端口露懒,對server端21端口發(fā)起連接
- 客戶端開始監(jiān)聽 N+1端口;
- 服務端會主動以20端口連接到客戶端的N+1端口砂心。
主動模式的優(yōu)點:
服務端配置簡單懈词,利于服務器安全管理,服務器只需要開放21端口
主動模式的缺點:
如果客戶端開啟了防火墻辩诞,或客戶端處于內(nèi)網(wǎng)(NAT網(wǎng)關之后)坎弯, 那么服務器對客戶端端口發(fā)起的連接可能會失敗
被動模式:
被動模式工作過程:
- 客戶端以隨機非特權(quán)端口連接服務端的21端口
- 服務端開啟一個非特權(quán)端口為被動端口,并返回給客戶端
- 客戶端以非特權(quán)端口+1的端口主動連接服務端的被動端口
被動模式缺點:
服務器配置管理稍顯復雜译暂,不利于安全抠忘,服務器需要開放隨機高位端口以便客戶端可以連接,因此大多數(shù)FTP服務軟件都可以手動配置被動端口的范圍
被動模式的優(yōu)點:
對客戶端網(wǎng)絡環(huán)境沒有要求
2外永、搭建客戶端通過【主動模式】連接服務器
服務器端配置(以下配置默認為有公網(wǎng)ip的服務器):
①安全組入方向映射:TCP/21端口
開別的端口會出現(xiàn):ftplib.error_perm: 501 Rejected data connection to foreign address xxx.
②安全組出方向打開允許TCP所有端口
③pip3 install pyftpdlib
主動模式下崎脉,服務器端代碼
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
# filepath = r"F:\videos"
filepath = "/root/workspace/zys/ftpfiles"
# 新建一個用戶組
authorizer = DummyAuthorizer()
# 將用戶名,密碼伯顶,指定目錄囚灼,權(quán)限 添加到里面
authorizer.add_user("xxx", "xxx", filepath, perm="elradfmwM")
# 這個是添加匿名用戶,任何人都可以訪問,如果去掉的話祭衩,需要輸入用戶名和密碼灶体,可以自己嘗試
# authorizer.add_anonymous(filepath)
handler = FTPHandler
handler.authorizer = authorizer
# 開啟服務器
port = 21
server = FTPServer(("0.0.0.0", port), handler)
server.serve_forever()
# 讀取權(quán)限
# "e" ——更改目錄(CWD,CDUP命令)
# "l" ——列表文件(LIST掐暮,NLST蝎抽,STAT,MLSD路克,MLST织中,SIZE命令)
# "r" ——從服務器檢索文件(RETR命令)
# 寫入權(quán)限
# "a" ——將數(shù)據(jù)追加到現(xiàn)有文件(APPE命令)
# "d" ——刪除文件或目錄(DELE锥涕,RMD命令)
# "f" ——重命名文件或目錄(RNFR,RNTO命令)
# "m" ——創(chuàng)建目錄(MKD命令)
# "w" ——將文件存儲到服務器(STOR狭吼,STOU命令)
# "M"——更改文件模式/權(quán)限(SITE CHMOD命令)
# "T"——更改文件修改時間(SITE MFMT命令)
主動模式下层坠,客戶端代碼(被動模式加了try-catch,可以參考)
from ftplib import FTP
import datetime
def ftpconnect(host, port, username, password):
ftp = FTP()
ftp.set_debuglevel(2)
ftp.connect(host, port)
ftp.login(username, password)
ftp.set_pasv(False) ########################主動模式
print(ftp.getwelcome())
return ftp
def downloadfile(ftp, remotepath, localpath):
# 從ftp下載文件
bufsize = 1024
fp = open(localpath, 'wb')
ftp.retrbinary('RETR ' + remotepath, fp.write, bufsize)
ftp.set_debuglevel(0)
fp.close()
def uploadfile(ftp, localpath, remotepath):
# 從本地上傳文件到ftp
bufsize = 1024
fp = open(localpath, 'rb')
ftp.storbinary('STOR ' + remotepath, fp, bufsize)
ftp.set_debuglevel(0)
fp.close()
if __name__ == "__main__":
ip = "xxxxxxx"
ftp = ftpconnect(ip, 21, "xxx", "xxx")
local_file = r'F:\videos\2023-02-04_01-58-09.mp4'
for i in range(2):
target_file = str(i) + 'xx.mp4'
uploadfile(ftp, local_file, target_file)
# downloadfile(ftp, "VID_20210830_103249.mp4", "11.mp4")
ftp.quit()
3刁笙、搭建客戶端通過【被動模式】連接服務器
服務器端配置(以下配置默認為有公網(wǎng)ip的服務器):
①安全組-入方向映射:TCP/21端口破花,和passive_ports設定的主動模式下端口范圍
②安全組出方向不用設置
③pip3 install pyftpdlib
被動模式下,服務器端代碼
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
# filepath = r"F:\videos"
filepath = "/root/workspace/zys/ftpfiles"
# 新建一個用戶組
authorizer = DummyAuthorizer()
# 將用戶名疲吸,密碼座每,指定目錄,權(quán)限 添加到里面
authorizer.add_user("xxx", "xxx", filepath, perm="elradfmwM")
# 這個是添加匿名用戶,任何人都可以訪問摘悴,如果去掉的話峭梳,需要輸入用戶名和密碼,可以自己嘗試
# authorizer.add_anonymous(filepath)
handler = FTPHandler
handler.authorizer = authorizer
#
#*******************添加被動端口范圍, client主動模式下蹂喻,不需要設置********************************
handler.passive_ports = range(38300, 38301)
#***********************************************************************
# 開啟服務器
port = 21
server = FTPServer(("0.0.0.0", port), handler)
server.serve_forever()
# 讀取權(quán)限
# "e" ——更改目錄(CWD葱椭,CDUP命令)
# "l" ——列表文件(LIST,NLST口四,STAT孵运,MLSD,MLST蔓彩,SIZE命令)
# "r" ——從服務器檢索文件(RETR命令)
# 寫入權(quán)限
# "a" ——將數(shù)據(jù)追加到現(xiàn)有文件(APPE命令)
# "d" ——刪除文件或目錄(DELE治笨,RMD命令)
# "f" ——重命名文件或目錄(RNFR,RNTO命令)
# "m" ——創(chuàng)建目錄(MKD命令)
# "w" ——將文件存儲到服務器(STOR赤嚼,STOU命令)
# "M"——更改文件模式/權(quán)限(SITE CHMOD命令)
# "T"——更改文件修改時間(SITE MFMT命令)
被動模式下旷赖,客戶端代碼(重寫makepasv方法)
from ftplib import FTP
import datetime
# 重寫makepasv方法, *************非常重要***************
# 作用是為了數(shù)據(jù)傳輸時使用服務器被動模式下返回的ip和port
# 防止出現(xiàn)卡在:*resp* '227 Entering passive mode (192,168,1,1x,xx,xxx).'
class MyFtp(FTP):
def makepasv(self):
host, port = super(MyFtp, self).makepasv()
host = self.sock.getpeername()[0]
print(host, port)
return host, port
def ftpconnect(host, port, username, password):
connectStatus = True
ftp = MyFtp()
# ftp.set_debuglevel(2)
try:
ftp.connect(host, port)
ftp.login(username, password)
print("*********************************************************", ftp.getwelcome())
except ConnectionRefusedError as e:
print("ftp服務連接失敗!")
connectStatus = False
return connectStatus, ftp
def downloadfile(ip, port, remotepath, localpath):
# ftp連接
connectStatus, ftp = ftpconnect(ip, port, "xxx", "xxx")
if not connectStatus:
pass
try:
# 從ftp下載文件
bufsize = 1024
fp = open(localpath, 'wb')
ftp.retrbinary('RETR ' + remotepath, fp.write, bufsize)
ftp.set_debuglevel(0)
fp.close()
except EOFError as e:
print("FTP服務異常更卒,傳輸失數确酢!")
except ConnectionAbortedError as e:
print("FTP服務異常逞壁,傳輸失斄骷谩锐锣!")
except TimeoutError as e:
print("FTP服務異常腌闯,傳輸失敗雕憔!")
except Exception as e:
print("FTP服務異常姿骏,傳輸失敗斤彼!")
def uploadfile(ip, port, localpath, remotepath):
# ftp連接
connectStatus, ftp = ftpconnect(ip, port, "xxx", "xxx")
if not connectStatus:
pass
try:
# 從本地上傳文件到ftp
bufsize = 1024
fp = open(localpath, 'rb')
ftp.storbinary('STOR ' + remotepath, fp, bufsize)
ftp.set_debuglevel(0)
fp.close()
ftp.quit()
except EOFError as e:
print("FTP服務異常分瘦,傳輸失斦盒骸!")
except ConnectionAbortedError as e:
print("FTP服務異常嘲玫,傳輸失斣檬!")
except TimeoutError as e:
print("FTP服務異常去团,傳輸失斅盏!")
except Exception as e:
print("FTP服務異常土陪,傳輸失斨绾埂!")
import time
if __name__ == "__main__":
ip = "xxxxx"
port = xxx # 可以是云服務的21端口鬼雀,也可以是服務器21端口映射到外網(wǎng)的端口
local_file = r'F:\videos\2023-02-04_01-58-09.mp4'
for i in range(5):
target_file = str(i) + 'a.mp4'
try:
uploadfile(ip, port, local_file, target_file)
except Exception as e:
print(e)
time.sleep(5)
# downloadfile(ftp, "VID_20210830_103249.mp4", "11.mp4")
本次過程中出現(xiàn)的錯誤:
①主動模式:ftplib.error_perm: 501 Rejected data connection to foreign address 192.168.1.xxx.11.
②被動模式顷窒,卡在resp '227 Entering passive mode (192,168,1,1x,xx,xxx).'