使用 python 快速建立 FTP 服务器和客户端

使用 python 快速建立 FTP 服务器和客户端

在运维工作中我们可能经常需要共享或传输文件,最简单快捷的方法就是搭建一个FTP服务器。那么我们有必要先了解一下什么是ftp。

FTP 就是 File Transfer Protocol(文件传输协议) 它运行在TCP协议之上,使用两个端口:一个是数据端口,一个是命令端口,也称控制端口。默认情况下20是数据端口,21是命令端口。FTP有两种传输模式:

  1. 主动模式:
    主动模式下,客户端从任意的非特殊端口n(大于1023的端口)连接FTP服务器的命令端口(默认是21),然后在n+1端口监听。用图表示如下:

    《使用 python 快速建立 FTP 服务器和客户端》 image

在第1步中,客户端的命令端口与FTP服务器的命令端口建立连接,并发送命令“PORT 1027”。然后在第2步中,FTP服务器给客户端的命令端口返回一个”ACK”。在第3步中,FTP服务器发起一个从它自己的数据端口(20)到客户端先前指定的数据端口(1027)的连接,最后客户端在第4步中给服务器端返回一个”ACK”。

主动方式FTP的主要问题实际上在于客户端。FTP的客户端并没有实际建立一个到服务器数据端口的连接,它只是简单的告诉服务器自己监听的端口号,服务器再回来连接客户端这个指定的端口。对于客户端的防火墙来说,这是从外部系统建立到内部客户端的连接,这是通常会被阻塞的。

  1. 被动模式:
    为了解决服务器发起到客户的连接的问题,人们开发了被动方式,或者叫做PASV,当客户端通知服务器它处于被动模式时才启用。在被动方式FTP中,命令连接和数据连接都由客户端发起。当开启一个FTP连接时,客户端打开两个任意的非特权本地端口(大于 1023)。第一个端口连接服务器的21端口,但与主动方式的FTP不同,客户端不会提交PORT命令并允许服务器来回连它的数据端口,而是提交PASV命令。这样做的结果是服务器会开启一个任意的非特权端口,并发送PORT P命令给客户端。然后客户端发起从本地端口N+1到服务器的端口P的连接用来传送数据。
    用图表示如下所示:

《使用 python 快速建立 FTP 服务器和客户端》 image

简单总结
主动FTP对FTP服务器的管理有利,但对客户端的管理不利。因为FTP服务器企图与客户端的高位随机端口建立连接,而这个端口很有可能被客户端的防火墙阻塞掉。被动FTP对FTP客户端的管理有利,但对服务器端的管理不利。因为客户端要与服务器端建立两个连接,其中一个连到一个高位随机端口,而这个端口很有可能被服务器端的防火墙阻塞掉。

简单了解了FTP之后接下来我们首先使用Python搭建一个FTP 服务器

搭建 FTP 服务器

  1. 安装 pyftpdlig
pip install pyftpdlib
  1. 使用pyftpdlib搭建一个服务器 myftpserver1.py
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')
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


# 监听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()

执行 python myftpserver1.py

《使用 python 快速建立 FTP 服务器和客户端》 1.png

在程序目录下会看到生成了myftpserver.log,文件内容与终端打印内容一致。

现在我们在命令窗口进行登陆测试

《使用 python 快速建立 FTP 服务器和客户端》 2.png

服务器窗口如下所示

《使用 python 快速建立 FTP 服务器和客户端》 3.png

用户的权限说明

读权限

标识说明
e改变文件目录
l列出文件
r从服务器接收文件

写权限

标识说明
a文件上传
d删除文件
f文件重命名
m创建文件
w写权限
M文件传输模式(通过FTP设置文件权限 )

注意
在winddows系统中可能会有乱码,原因是pyftpdlib内部使用utf8,而windows使用gbk,解决方法如下:
修改pyftpdlib包中的filesystems.py,找到

yield line.encode('utf8', self.cmd_channel.unicode_errors)

共有两处,将此处的utf8改为gbk,
修改pyftpdlib包中的handlers.py,找到FTPHandler的decode方法

return bytes.decode('utf8', self.unicode_errors)

将此处的utf8改为gbk即可解决乱码问题。

更快的操作
如果我们只想在当前目录建立一个ftp服务器供别人下载文件,那么在当前路径直接执行

python -n pyftpdlib -p 21

可以看到有如下结果

《使用 python 快速建立 FTP 服务器和客户端》 4.png

那么问题来了,如何使用python操作 FTP 服务器上的文件呢?

编写 FTP 客户端程序

#-*- encoding:utf-8 -*-
from ftplib import FTP
#登陆FTP
ftp = FTP(host='localhost',user='user',passwd='12345')
#设置编码方式,由于在windows系统,设置编码为gbk
ftp.encoding = 'gbk'
#切换目录
ftp.cwd('test')
#列出文件夹的内容
ftp.retrlines('LIST') # ftp.dir()
#下载文件_vimrc
ftp.retrbinary('RETR _vimrc', open('_vimrc', 'wb').write)
#上传文件 _vimrc服务器端文件名为_vimrc3
ftp.storbinary('STOR _vimrc3', open('_vimrc', 'rb'))
#查看目录下的文件详情
for f in ftp.mlsd(path='/test'):
    print(f)

代码链接

    原文作者:somenzz
    原文地址: https://www.jianshu.com/p/f4663c71fbca
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞