Python搭建FTP服务器与客户端
目录
FTP工作原理
熟悉FTP的读者可能会觉得这个太简单了,直接在网上下载软件安装运行就可以了,客户端和服务器都有,但是只能满足一些简单的工作需求。如果我们通过写Python代码搭建FTP服务器和客户端,就能实现一些更为精细化的控制,如精细的访问权限配置、详细的日志记录等,根据工作经验,Python搭建FTP服务器也非常简单,而且更为稳定,下面就让我们一起来学习吧。
简单总结:主动方式对FTP服务器的管理有利,但对客户端的管理不利。因为FTP服务器企图与客户端的高位随机端口建立连接,而这个端口很有可能被客户端的防火墙阻塞掉。被动方式对FTP客户端的管理有利,但对服务器端的管理不利。因为客户端要与服务器端建立两个连接,其中一个连到一个高位随机端口,而这个端口很有可能被服务器端的防火墙阻塞掉。
FTP的搭建
安装模块:
pip3 install pyftpdlib
如果Python3.7.0以上版本安装时报错ModuleNotFoundError: No module named '_ctypes',
原因在这里:https://www.jianshu.com/p/69681655309b
可以 执行命令:yum install libffi-devel -y
然后参照Centos7 安装python3将Python重新安装一遍即可。
服务器端
方法1:快速搭建一个简单的FTP服务器
python3 -m pyftpdlib -p 21
即可在执行命令所在的目录下建立一个端口为21的供下载文件的FTP服务器,
注意Linux系统需要root用户才能使用默认端口21,
建立之后我们可以远程利于windows文件管理器打开:
windows系统中目录文件名可能是乱码,原因是pyftpdlib内部使用utf8,而windows使用gbk,参照下面的步骤可解决windows系统的乱码问题:
windows系统解决乱码的办法:
首先,找到pyftpdlib源文件所在的目录。
>>> import pyftpdlib >>> pyftpdlib.__path__ ['C:\\Users\\xx\\projectA_env\\lib\\site-packages\\pyftpdlib']
其次,在目录pyftpdlib源文件所在的目录找到文件filesystems.py和handlers.py,先备份。
再次,打开filesystems.py,找到
yield line.encode('utf8', self.cmd_channel.unicode_errors)
共有两处,修改'utf8'为'gbk',保存并退出。
打开handlers.py,找到
return bytes.decode('utf8', self.unicode_errors)
修改utf8为gbk,保存并退出。
最后,验证乱码已解决。
方法二:搭建一个具有访问权限,可配置相关信息的FTP服务器(ftpserver.py)
python3 ftpserver.py
[I 2020-01-18 21:50:18] >>> starting FTP server on 0.0.0.0:21, pid=65456 <<< [I 2020-01-18 21:50:18] concurrency model: async [I 2020-01-18 21:50:18] masquerade (NAT) address: None [I 2020-01-18 21:50:18] passive ports: 2000->2332
ftpserver.py:
(以下为windows下的的代码,linux的只需把路径'd:/' 改成 ‘.’即可)
from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler,ThrottledDTPHandler from pyftpdlib.servers import FTPServer from pyftpdlib.log import LogFormatter import logging #记录日志,默认情况下日志仅输出到屏幕(终端),这里即输出到屏幕又输出到文件,方便日志查看 logger = logging.getLogger() logger.setLevel(logging.INFO) ch = logging.StreamHandler() fh = logging.FileHandler(filename='myftpserver.log',encoding='utf-8') #默认的方式是追加到文件 ch.setFormatter(LogFormatter()) fh.setFormatter(LogFormatter()) logger.addHandler(ch) #将日志输出至屏幕 logger.addHandler(fh) #将日志输出至文件 # 实例化虚拟用户,这是FTP验证首要条件 authorizer = DummyAuthorizer() # 添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限),可以为不同的用户添加不同的目录和权限 authorizer.add_user("user", "12345", "d:/", perm="elradfmw") # 添加匿名用户 只需要路径 authorizer.add_anonymous("d:/") # 初始化ftp句柄 handler = FTPHandler handler.authorizer = authorizer #添加被动端口范围 handler.passive_ports = range(2000, 2333) # 下载上传速度设置 dtp_handler = ThrottledDTPHandler dtp_handler.read_limit = 300 * 1024 #300kb/s dtp_handler.write_limit = 300 * 1024 #300kb/s handler.dtp_handler = dtp_handler # 监听ip 和 端口,linux里需要root用户才能使用21端口 server = FTPServer(("0.0.0.0", 21), handler) # 最大连接数 server.max_cons = 150 server.max_cons_per_ip = 15 # 开始服务,自带日志打印信息 server.serve_forever()
登录ftp并进行测试:
C:\Users\thinkpad>ftp 192.168.1.102 连接到 192.168.1.102。 220 pyftpdlib 1.5.5 ready. 530 Log in with USER and PASS first. 用户(192.168.1.102:(none)): user 331 Username ok, send password. 密码: 230 Login successful. ftp> dir 200 Active data connection established. 125 Data connection already open. Transfer starting. drwxrwxrwx 1 owner group 0 Oct 02 06:41 $RECYCLE.BIN drwxrwxrwx 1 owner group 0 Oct 19 00:09 .android drwxrwxrwx 1 owner group 4096 Nov 28 2018 360Rec drwxrwxrwx 1 owner group 0 Dec 21 06:43 BaiduYunDownload drwxrwxrwx 1 owner group 4096 Jun 16 2017 Biz drwxrwxrwx 1 owner group 0 Oct 21 06:48 Config.Msi dr-xr-xr-x 1 owner group 4096 Jan 13 01:09 Game drwxrwxrwx 1 owner group 4096 Dec 02 14:05 Life drwxrwxrwx 1 owner group 8192 Jul 01 2019 MyStore dr-xr-xr-x 1 owner group 4096 Nov 25 02:57 OneDrive drwxrwxrwx 1 owner group 49152 Jan 18 06:27 Program Files dr-xr-xr-x 1 owner group 4096 Jan 13 01:09 Project drwxrwxrwx 1 owner group 0 Jan 13 2018 PycharmProjects drwxrwxrwx 1 owner group 0 Dec 10 02:33 QLDownload drwxrwxrwx 1 owner group 0 Jun 26 2016 System Volume Information dr-xr-xr-x 1 owner group 4096 Jan 13 01:09 Tech drwxrwxrwx 1 owner group 0 Oct 04 09:25 VS09_PROJECTS drwxrwxrwx 1 owner group 0 Oct 04 09:25 VS10_PROJECTS drwxrwxrwx 1 owner group 0 Nov 17 00:15 WUDownloadCache drwxrwxrwx 1 owner group 8192 Jan 15 12:49 Work drwxrwxrwx 1 owner group 0 Dec 15 00:13 d94083babee197af8beff6f0c833622e dr-xr-xr-x 1 owner group 4096 Jan 17 08:16 teaching drwxrwxrwx 1 owner group 4096 Jan 17 01:29 tttt 226 Transfer complete.
客户端
# -*- encoding:utf-8 -*- from ftplib import FTP #登陆FTP ftp = FTP(host='10.0.0.30',user='user',passwd='12345') #设置编码方式,由于在windows系统,设置编码为gbk ftp.encoding = 'gbk' # 切换目录 ftp.cwd('test') #列出文件夹的内容 ftp.retrlines('LIST') # ftp.dir() #下载文件 note.txt ftp.retrbinary('RETR note.txt', open('note.txt', 'wb').write) #上传文件 ftpserver.py ftp.storbinary('STOR sample.txt', open('sample.txt', 'rb')) #查看目录下的文件详情 for f in ftp.mlsd(path='/test'): print(f)