python实现FTP服务器服务的方法


Posted in Python onApril 11, 2017

FTP服务的主动模式和被动模式

在开始之前,先聊一下FTP的主动模式和被动模式,两者的区别 , 用两张图来表示可能会更加清晰一些:

主动模式:

python实现FTP服务器服务的方法

主动模式工作过程:

1. 客户端以随机非特权端口N,就是大于1024的端口,对server端21端口发起连接

2. 客户端开始监听 N+1端口;

3. 服务端会主动以20端口连接到客户端的N+1端口。

主动模式的优点:

服务端配置简单,利于服务器安全管理,服务器只需要开放21端口

主动模式的缺点:

如果客户端开启了防火墙,或客户端处于内网(NAT网关之后), 那么服务器对客户端端口发起的连接可能会失败

被动模式:

python实现FTP服务器服务的方法

被动模式工作过程:

1. 客户端以随机非特权端口连接服务端的21端口

2. 服务端开启一个非特权端口为被动端口,并返回给客户端

3. 客户端以非特权端口+1的端口主动连接服务端的被动端口

被动模式缺点:

服务器配置管理稍显复杂,不利于安全,服务器需要开放随机高位端口以便客户端可以连接,因此大多数FTP服务软件都可以手动配置被动端口的范围

被动模式的优点:对客户端网络环境没有要求

了解了FTP之后,开始使用python来实现FTP服务

准备工作

本次使用python版本:python 3.4.3

安装模块 pyftpdlib

pip3 install pyftpdlib

创建代码文件 FtpServer.py

代码

实现简单的本地验证

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

#实例化虚拟用户,这是FTP验证首要条件
authorizer = DummyAuthorizer()

#添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限)
authorizer.add_user('user', '12345', '/home/', perm='elradfmw')

#添加匿名用户 只需要路径
authorizer.add_anonymous('/home/huangxm')

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

#监听ip 和 端口,因为linux里非root用户无法使用21端口,所以我使用了2121端口
server = FTPServer(('192.168.0.108', 2121), handler)

#开始服务
server.serve_forever()

开启服务

$python FtpServer.py

测试一下:

python实现FTP服务器服务的方法

输入个错误密码试试:

python实现FTP服务器服务的方法

验证不通过,无法登录 。

但这似乎是主动模式的FTP ,如何实现被动模式呢?

通过以下代码添加被动端口:

handler.passive_ports = range(2000,2333)

完整代码:

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

#实例化虚拟用户,这是FTP验证首要条件
authorizer = DummyAuthorizer()

#添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限)
authorizer.add_user('user', '12345', '/home/', perm='elradfmw')

#添加匿名用户 只需要路径
authorizer.add_anonymous('/home/huangxm')

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

#添加被动端口范围
handler.passive_ports = range(2000, 2333)

#监听ip 和 端口
server = FTPServer(('192.168.0.108', 2121), handler)

#开始服务
server.serve_forever()

开启服务,可以看到被动端口的信息:

$ python FtpServer.py 
[I 2017-01-11 15:18:37] >>> starting FTP server on 192.168.0.108:2121, pid=46296 <<<
[I 2017-01-11 15:18:37] concurrency model: async
[I 2017-01-11 15:18:37] masquerade (NAT) address: None
[I 2017-01-11 15:18:37] passive ports: 2000->2332

FTP用户管理:

通过上面的实践,FTP服务器已经可以正常工作了,但是如果需要很多个FTP用户呢,怎么办呢? 每个用户都写一遍吗?

其实我们可以定义一个用户文件user.py

#用户名   密码    权限     目录
# root   12345   elradfmwM  /home
huangxm   12345   elradfmwM  /home

然后遍历该文件,将不以#开头的行加入到user_list列表中

完整代码:

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


def get_user(userfile):
  #定义一个用户列表
  user_list = []
  with open(userfile) as f:
    for line in f:
      print(len(line.split()))
      if not line.startswith('#') and line:
        if len(line.split()) == 4: 
          user_list.append(line.split())
        else:
          print("user.conf配置错误")
  return user_list

#实例化虚拟用户,这是FTP验证首要条件
authorizer = DummyAuthorizer()

#添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限)
#authorizer.add_user('user', '12345', '/home/', perm='elradfmw')
user_list = get_user('/home/huangxm/test_py/FtpServer/user.conf')
for user in user_list:
  name, passwd, permit, homedir = user
  try:
    authorizer.add_user(name, passwd, homedir, perm=permit)
  except Exception as e:
    print(e)

#添加匿名用户 只需要路径
authorizer.add_anonymous('/home/huangxm')

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

#添加被动端口范围
handler.passive_ports = range(2000, 2333)

#监听ip 和 端口
server = FTPServer(('192.168.0.108', 2121), handler)

#开始服务
server.serve_forever()

到这里,FTP 服务已经完成了。

规范一下代码

首先创建conf目录,存放settings.py和user.py

目录结构(cache里面的不用管):

python实现FTP服务器服务的方法

setting.py

ip = '0.0.0.0'

port = '2121'

#上传速度 300kb/s
max_upload = 300 * 1024

#下载速度 300kb/s
max_download = 300 * 1024

#最大连接数
max_cons = 150

#最多IP数
max_per_ip = 10

#被动端口范围,注意被动端口数量要比最大IP数多,否则可能出现无法连接的情况
passive_ports = (2000, 2200)

#是否开启匿名访问 on|off
enable_anonymous = 'off'
#匿名用户目录
anonymous_path = '/home/huangxm'

#是否开启日志 on|off
enable_logging = 'off'
#日志文件
loging_name = 'pyftp.log'

#欢迎信息
welcome_msg = 'Welcome to my ftp'

user.py

#用户名   密码    权限     目录
#root   12345   elradfmwM  /home/
huangxm   12345   elradfmwM  /home/
test    12345   elradfmwM  /home/huangxm

FtpServer.py

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


def get_user(userfile):
  #定义一个用户列表
  user_list = []
  with open(userfile) as f:
    for line in f:
      if not line.startswith('#') and line:
        if len(line.split()) == 4: 
          user_list.append(line.split())
        else:
          print("user.conf配置错误")
  return user_list

def ftp_server():
  #实例化虚拟用户,这是FTP验证首要条件
  authorizer = DummyAuthorizer()
  
  #添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限)
  #authorizer.add_user('user', '12345', '/home/', perm='elradfmw')
  user_list = get_user('conf/user.py')
  for user in user_list:
    name, passwd, permit, homedir = user
    try:
      authorizer.add_user(name, passwd, homedir, perm=permit)
    except Exception as e:
      print(e)

  #添加匿名用户 只需要路径
  if settings.enable_anonymous == 'on':
    authorizer.add_anonymous(settings.anonymous_path)
  
  #下载上传速度设置
  dtp_handler = ThrottledDTPHandler
  dtp_handler.read_limit = settings.max_download
  dtp_handler.write_limit = settings.max_upload

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

  #日志记录
  if settings.enable_logging == 'on':
    logging.basicConfig(filename=settings.loging_name, level=logging.INFO)

  #欢迎信息
  handler.banner = settings.welcome_msg
  

  #添加被动端口范围
  handler.passive_ports = range(settings.passive_ports[0], settings.passive_ports[1])

  #监听ip 和 端口
  server = FTPServer((settings.ip, settings.port), handler)
  
  #最大连接数
  server.max_cons = settings.max_cons
  server.max_cons_per_ip = settings.max_per_ip
  
  #开始服务
  print('开始服务')
  server.serve_forever()

if __name__ == "__main__":
  ftp_server()

最后,说一下权限问题

读权限 :

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

写权限 :

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

M 示例:

python实现FTP服务器服务的方法

到服务器上查看一下权限:

python实现FTP服务器服务的方法

可以看到权限已经被修改了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
解决python2.7 查询mysql时出现中文乱码
Oct 09 Python
Python基于ThreadingTCPServer创建多线程代理的方法示例
Jan 11 Python
python同时遍历数组的索引和值的实例
Nov 15 Python
记一次python 内存泄漏问题及解决过程
Nov 29 Python
对python3标准库httpclient的使用详解
Dec 18 Python
python腾讯语音合成实现过程解析
Aug 01 Python
Windows10下Tensorflow2.0 安装及环境配置教程(图文)
Nov 21 Python
python实现画出e指数函数的图像
Nov 21 Python
pytorch:实现简单的GAN示例(MNIST数据集)
Jan 10 Python
django 多数据库及分库实现方式
Apr 01 Python
Python多线程:主线程等待所有子线程结束代码
Apr 25 Python
Python格式化输出--%s,%d,%f的代码解析
Apr 29 Python
python读写json文件的简单实现
Apr 11 #Python
Python实现Mysql数据库连接池实例详解
Apr 11 #Python
详解Python中类的定义与使用
Apr 11 #Python
python获取指定时间差的时间实例详解
Apr 11 #Python
一个基于flask的web应用诞生 组织结构调整(7)
Apr 11 #Python
一个基于flask的web应用诞生 记录用户账户登录状态(6)
Apr 11 #Python
一个基于flask的web应用诞生 用户注册功能开发(5)
Apr 11 #Python
You might like
php 读取文件头判断文件类型的实现代码
2013/08/05 PHP
php类的扩展和继承用法实例
2015/06/20 PHP
Yii2针对指定url的生成及图片等的引入方法小结
2016/07/18 PHP
PHP仿微信多图片预览上传实例代码
2016/09/13 PHP
详解Yaf框架PHPUnit集成测试方法
2017/12/27 PHP
关于二级域名下使用一级域名下的COOKIE的问题
2011/11/07 Javascript
解析js如何获取当前url中的参数值并复制给input
2013/06/23 Javascript
javascript 拷贝节点cloneNode()使用介绍
2014/04/03 Javascript
ajax提交表单实现网页无刷新注册示例
2014/05/08 Javascript
jQuery实现的一个自定义Placeholder属性插件
2014/08/11 Javascript
Egret引擎开发指南之创建项目
2014/09/03 Javascript
JS组件Bootstrap dropdown组件扩展hover事件
2016/04/17 Javascript
Jquery中map函数的用法
2016/06/03 Javascript
基于CSS3和jQuery实现跟随鼠标方位的Hover特效
2016/07/25 Javascript
vue 微信授权登录解决方案
2018/04/10 Javascript
分享一个vue项目“脚手架”项目的实现步骤
2019/05/26 Javascript
js单线程的本质 Event Loop解析
2019/10/29 Javascript
JS实现关闭小广告特效
2021/01/29 Javascript
vue组件内部引入外部js文件的方法
2020/01/18 Javascript
微信小程序仿抖音视频之整屏上下切换功能的实现代码
2020/05/24 Javascript
解决vue里a标签值解析变量,跳转页面,前面加默认域名端口的问题
2020/07/22 Javascript
[00:47]TI7不朽珍藏III——沙王不朽展示
2017/07/15 DOTA
理解Python垃圾回收机制
2016/02/12 Python
Python for Informatics 第11章之正则表达式(二)
2016/04/21 Python
老生常谈python的私有公有属性(必看篇)
2017/06/09 Python
Python编程实现使用线性回归预测数据
2017/12/07 Python
Flask实现图片的上传、下载及展示示例代码
2018/08/03 Python
对python多线程与global变量详解
2018/11/09 Python
Python之京东商品秒杀的实现示例
2021/01/06 Python
Myholidays美国:在线旅游网站
2019/08/16 全球购物
FC-Moto丹麦:欧洲最大的摩托车服装和头盔商店之一
2019/08/20 全球购物
法国在线药房:Shop Pharmacie
2019/11/26 全球购物
关联、聚合(Aggregation)以及组合(Composition)的区别
2012/02/29 面试题
小学感恩节活动总结
2015/03/24 职场文书
2016党员干部廉洁自律心得体会
2016/01/13 职场文书
《中彩那天》教学反思
2016/02/24 职场文书