日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python实现FTP服务器和客户端

發(fā)布時間:2025/3/15 python 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python实现FTP服务器和客户端 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

基礎知識

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

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

FTP主動模式

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

然后開放N+1號端口進行監(jiān)聽,并向服務器發(fā)出PORT?N+1命令。

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

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

主動模式的優(yōu)點:

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

主動模式的缺點:

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

FTP被動模式

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

然后向服務器發(fā)送PASV命令,通知服務器自己處于被動模式。

服務器收到命令后,會開放一個大于1024的端口P進行監(jiān)聽,然后用PORT?P命令通知客戶端,自己的數(shù)據(jù)端口是P。

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

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

被動模式缺點:

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

被動模式的優(yōu)點:

對客戶端網(wǎng)絡環(huán)境沒有要求

?

使用python來實現(xiàn)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"?=將數(shù)據(jù)追加到現(xiàn)有文件(APPE命令)

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

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

"m"?=創(chuàng)建目錄(MKD命令)

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

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

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

開啟被動端口模式

#添加被動端口范圍 handler.passive_ports = range(8300, 8500) 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:/#------------ftpdemofrom pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler, ThrottledDTPHandler from pyftpdlib.servers import FTPServer import configparser import loggingIP = '127.0.0.1'PORT = '2121'# 上傳速度 100kb/s MAX_UPLOAD = 100 * 1024# 下載速度 100kb/s MAX_DOWNLOAD = 100 * 1024# 最大連接數(shù) MAX_CONS = 100# 最多IP數(shù) MAX_PER_IP = 10# 被動端口范圍,注意被動端口數(shù)量要比最大IP數(shù)多,否則可能出現(xiàn)無法連接的情況 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# 監(jiān)聽ip 和 端口 server = FTPServer((IP, PORT), handler)# 最大連接數(shù) server.max_cons = MAX_CONS server.max_cons_per_ip = MAX_PER_IP# 開始服務 print('FTP開始服務 ', (IP, PORT)) server.serve_forever()

?

?

基于twisted

#!/usr/bin/env python # -*- coding: utf-8 -*- """a very simple ftp server by twisted """ __author__ = "Bobning(nb5550606@gmail.com)" import sys, os sys.path.append('../../..') os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' from twisted.protocols import ftp from twisted.cred import portal, checkers, credentials, error as credError from twisted.internet import reactor, defer from zope.interface import implements from twisted.python import filepath from django.contrib.auth import authenticate from django.contrib.auth.models import User class UserChecker: implements(checkers.ICredentialsChecker) credentialInterfaces = (credentials.IUsernamePassword,) def __init__(self): "passwords: a dict-like object mapping usernames to passwords" def requestAvatarId(self, credentials): user = authenticate(username=credentials.username, password=credentials.password) if user is not None: if user.is_active: return defer.succeed(credentials.username) else: return defer.fail(credError.UnauthorizedLogin("access denied")) else: return defer.fail(credError.UnauthorizedLogin("No such user")) class MyFTPRealm: implements(portal.IRealm) def __init__(self, anonymousRoot): self.anonymousRoot = filepath.FilePath(anonymousRoot) def requestAvatar(self, avatarId, mind, *interfaces): for iface in interfaces: if iface is ftp.IFTPShell: if avatarId is checkers.ANONYMOUS: avatar = ftp.FTPAnonymousShell(self.anonymousRoot) else: try: user = User.objects.get(username=avatarId) ftpdir = user.ftp.all()[0].ftpdir except: raise "沒有該用戶" avatar = ftp.FTPShell(filepath.FilePath(ftpdir.encode("utf-8"))) return ftp.IFTPShell, avatar, getattr(avatar, "logout", lambda:None) raise NotImplementedError("only IFTPShell interface is supported by this realm") class MyFtpServer(ftp.FTP): def __init__(self, *args, **kw): super(ftp.FTP, self).__init__(*args, **kw) def dataReceived(self, data): self.transport.write(data) if __name__ == "__main__": p = portal.Portal(MyFTPRealm("")) p.registerChecker(UserChecker()) factory = ftp.FTPFactory(MyFtpServer()) factory.portal = p reactor.listenTCP(2121, factory) reactor.run()

?

客戶端實現(xiàn)

import ftplib import sys#獲取服務器的ip地址(如192.168.1.107),使用sys.argv可以從命令行參數(shù)里面獲取 if len(sys.argv) < 2:tmp = input("please input server address:")sys.argv.append(tmp) server_address = sys.argv[1] #創(chuàng)建FTP實例,并顯示歡迎界面 ftp = ftplib.FTP(server_address) print(ftp.getwelcome()) #登錄,輸入服務器里添加過的用戶名和口令 ftp.login('user', 'pass')#文件上傳 def upload(fname):fd = open(fname, 'rb')new_name = input("input new name:")#以二進制的形式上傳ftp.storbinary("STOR %s" % new_name, fd)fd.close()print("upload finished")#文件下載 def download(fname):#構建文件的存儲路徑,這里用的是D盤,可以自行設置new_path = "D:\\FTPdownload\\" + fnamefd = open(new_path, 'wb')#以二進制形式下載,注意第二個參數(shù)是fd.write,上傳時是fdftp.retrbinary("RETR %s" % fname, fd.write)fd.close()print("download finished")def main():#選擇操作,上傳、下載、退出op = input("what do you want?(u/d/q)")if op == "u":#輸入文件完整路徑,必要時可以用絕對路徑fname = input("input the file of path:")upload(fname)elif op == "d":fname = input("input the file name:")download(fname)else:print("quit now!")ftp.quit()if __name__ == '__main__':main()

附帶一些ftplib庫的相關操作:

ftp.cwd(pathname) # 設置FTP當前操作的路徑 ftp.dir() # 顯示目錄下所有目錄的信息 ftp.nlst() # 獲取目錄下的文件 ftp.mkd(pathname) # 新建遠程目錄 ftp.rmd(dirname) # 刪除遠程目錄 ftp.pwd() # 返回當前所在位置 ftp.delete(filename) # 刪除遠程文件 ftp.rename(old_name, new_name) #將fromname改為toname ftp.storbinary('STOR filename.txt',file_handel,[bufsize]) # 上傳目標文件,最后一個參數(shù)可以不填 ftp。retrbinary('RETR filename.txt',file_handel,[bufsize]) # 下載FTP文件

?

總結

以上是生活随笔為你收集整理的Python实现FTP服务器和客户端的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。