python實現FTP服務器


基礎知識

FTP只通過TCP連接,FTP不同於其他服務的是它使用了兩個端口, 一個數據端口和一個命令端口(或稱為控制端口)。

通常21端口是命令端口,20端口是數據端口。當混入主動/被動模式的概念時,數據端口就有可能不是20了

FTP主動模式

在主動模式下,FTP客戶端隨機開啟一個大於1024的端口N向服務器的21號端口發起連接,

然后開放N+1號端口進行監聽,並向服務器發出PORT N+1命令。

服務器接收到命令后,會用其本地的FTP數據端口(通常是20)來連接客戶端指定的端口N+1,進行數據傳輸。

 

 

  • FTP服務器命令(21)端口接受客戶端任意端口(客戶端初始連接)
  • FTP服務器命令(21)端口到客戶端端口(>1023)(服務器響應客戶端命令)
  • FTP服務器數據(20)端口到客戶端端口(>1023)(服務器初始化數據連接到客戶端數據端口)
  • FTP服務器數據(20)端口接受客戶端端口(>1023)(客戶端發送ACK包到服務器的數據端口)

主動模式的優點:

服務端配置簡單,利於服務器安全管理,服務器只需要開放21端口

主動模式的缺點:

如果客戶端開啟了防火牆,或客戶端處於內網(NAT網關之后), 那么服務器對客戶端端口發起的連接可能會失敗

 

FTP被動模式

在被動模式下,FTP庫戶端隨機開啟一個大於1024的端口N向服務器的21號端口發起連接,同時會開啟N+1號端口。

然后向服務器發送PASV命令,通知服務器自己處於被動模式。

服務器收到命令后,會開放一個大於1024的端口P進行監聽,然后用PORT P命令通知客戶端,自己的數據端口是P。

客戶端收到命令后,會通過N+1號端口連接服務器的端口P,然后在兩個端口之間進行數據傳輸

  • FTP服務器命令(21)端口接受客戶端任意端口(客戶端初始連接)
  • FTP服務器命令(21)端口到客戶端端口(>1023)(服務器響應客戶端命令)
  • FTP服務器數據端口(>1023)接受客戶端端口(>1023)(客戶端初始化數據連接到服務器指定的任意端口)
  • FTP服務器數據端口(>1023)到客戶端端口(>1023)(服務器發送ACK響應和數據到客戶端的數據端口)

被動模式缺點:

服務器配置管理稍顯復雜,不利於安全,服務器需要開放隨機高位端口以便客戶端可以連接,因此大多數FTP服務軟件都可以手動配置被動端口的范圍

被動模式的優點:

對客戶端網絡環境沒有要求

總結

主動FTP:
     命令連接:客戶端 >1023端口 -> 服務器 21端口
     數據連接:客戶端 >1023端口 <- 服務器 20端口 

  被動FTP:
     命令連接:客戶端 >1023端口 -> 服務器 21端口
     數據連接:客戶端 >1023端口 -> 服務器 >1023端口 

使用python來實現FTP服務

安裝模塊 pyftpdlib

pip3 install pyftpdlib

教程

http://pyftpdlib.readthedocs.io/en/latest/tutorial.html

源碼

https://github.com/giampaolo/pyftpdlib

使用:

from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer

# 新建一個用戶組
authorizer = DummyAuthorizer()
# 將用戶名,密碼,指定目錄,權限 添加到里面
authorizer.add_user("fan", "root", "E:/", perm="elr")  # adfmw
# 這個是添加匿名用戶,任何人都可以訪問,如果去掉的話,需要輸入用戶名和密碼,可以自己嘗試
authorizer.add_anonymous("E:/")

handler = FTPHandler
handler.authorizer = authorizer
# 開啟服務器
server = FTPServer(("127.0.0.1", 21), handler)
server.serve_forever()

然后將程序運行起來,接下來看一下效果,在瀏覽器上ftp://localhost/

 

 

用戶權限

讀取權限:

"e" =更改目錄(CWD,CDUP命令)

"l" =列表文件(LIST,NLST,STAT,MLSD,MLST,SIZE命令)

"r" =從服務器檢索文件(RETR命令)

寫入權限:

"a" =將數據追加到現有文件(APPE命令)

"d" =刪除文件或目錄(DELE,RMD命令)

"f" =重命名文件或目錄(RNFR,RNTO命令)

"m" =創建目錄(MKD命令)

"w" =將文件存儲到服務器(STOR,STOU命令)

"M"=更改文件模式/權限(SITE CHMOD命令)

"T"=更改文件修改時間(SITE MFMT命令)

 

開啟被動端口模式

#添加被動端口范圍
handler.passive_ports = range(8300, 8500)

demo  

from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer

# 新建一個用戶組
authorizer = DummyAuthorizer()
# 將用戶名,密碼,指定目錄,權限 添加到里面
authorizer.add_user("test", "1234", "E:/", perm="elradfmw")  # adfmw
# 這個是添加匿名用戶,任何人都可以訪問,如果去掉的話,需要輸入用戶名和密碼,可以自己嘗試
authorizer.add_anonymous("E:/")

handler = FTPHandler
handler.authorizer = authorizer

#添加被動端口范圍
handler.passive_ports = range(8300, 8500)

# 開啟服務器
server = FTPServer(("127.0.0.1", 2121), handler)
server.serve_forever()

-----------輸出-----------------

[I 2018-08-06 15:37:16] >>> starting FTP server on 127.0.0.1:2121, pid=8564 <<<
[I 2018-08-06 15:37:16] concurrency model: async
[I 2018-08-06 15:37:16] masquerade (NAT) address: None
[I 2018-08-06 15:37:16] passive ports: 8300->8499
[I 2018-08-06 15:37:32] 127.0.0.1:54898-[] FTP session opened (connect)

 

 

讀取用戶列表,建立FTP

#-----------user.ini------

[alex]
password=123
perm=elradfmwM
home=D:/

[egon]
password=123456
perm=elradfmwM
home=D:/


#------------ftpdemo

from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler, ThrottledDTPHandler
from pyftpdlib.servers import FTPServer
import configparser
import logging

IP = '127.0.0.1'

PORT = '2121'

# 上傳速度  100kb/s
MAX_UPLOAD = 100 * 1024

# 下載速度 100kb/s
MAX_DOWNLOAD = 100 * 1024

# 最大連接數
MAX_CONS = 100

# 最多IP數
MAX_PER_IP = 10

# 被動端口范圍,注意被動端口數量要比最大IP數多,否則可能出現無法連接的情況
PASSIVE_PORTS = (8300, 8500)

# 是否開啟匿名訪問 on|off
ENABLE_ANONYMOUS = 'off'

# 匿名用戶目錄
ANONYMOUS_PATH = 'E:/DEVTOOL/'


# 日志文件
LOGING_NAME = 'pyftp.log'

# 歡迎信息
WELCOME_MSG = 'Welcome to my ftp'

# 新建一個用戶組
authorizer = DummyAuthorizer()

# 讀取用戶配置
config = configparser.ConfigParser()
config.read('user.ini')
user_list = config.sections()
for user in user_list:
    passwd = config[user]["password"]
    perm = config[user]["perm"]
    home_dir = config[user]["home"]
    # 將用戶名,密碼,指定目錄,權限 添加到里面
    authorizer.add_user(user, passwd, homedir=home_dir, perm=perm)

# 添加匿名用戶 只需要路徑
if ENABLE_ANONYMOUS == 'on':
    authorizer.add_anonymous(ANONYMOUS_PATH)

# 下載上傳速度設置
dtp_handler = ThrottledDTPHandler
dtp_handler.read_limit = MAX_DOWNLOAD
dtp_handler.write_limit = MAX_UPLOAD

# 初始化ftp句柄
handler = FTPHandler
handler.authorizer = authorizer

# 添加被動端口范圍
handler.passive_ports = range(PASSIVE_PORTS[0], PASSIVE_PORTS[1])


# 歡迎信息
handler.banner = WELCOME_MSG

# 監聽ip 和 端口
server = FTPServer((IP, PORT), handler)

# 最大連接數
server.max_cons = MAX_CONS
server.max_cons_per_ip = MAX_PER_IP

# 開始服務
print('FTP開始服務 ', (IP, PORT))
server.serve_forever()

 

 參考網站:

https://www.cnblogs.com/huangxm/p/6274645.html

 

  


免責聲明!

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



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