py-FTP服务器之四:ftp主程序

关于pyftpdlib建立 FTP服务器的详细内容:
py-FTP服务器之一:虚拟运行环境
py-FTP服务器之二:用户配置文件
py-FTP服务器之三:启用SSL连接
py-FTP服务器之四:ftp主程序
py-FTP服务器之五:其他

  • 主程序是ftp.py
  • ftp.py同级要有一个rootftp文件夹, 作为根目录, ftp上传来的文件全部丢里面

关于是否启用SSL加密和多进程的代码

# 是否启用ssl加密和多进程模式
USE_SSL = False  # 是否启用ftps加密传输,通过修改单独的文件设置,默认是不用ssl
if 'ssl' in argv:
    USE_SSL = True  # 如果要启用ssl,运行时要加参数 ssl
if 'mul' in argv:
    USE_MULTIPLE_PROCESS = True  # 开启多进程模式, 运行时要增加参数 mul

注意: 在启动程序时需要在后面加参数, 比如要启用ssl, 则应当输入python ftp.py ssl, 如果还要开启多进程, 则应输入python ftp.py ssl mul

MD5验证函数

这个函数是在官方给的基础上做了一些简化.

# 验证用户密码hash后是否与原来的一样,照着官方文档写的,修改了一点
class DummyMD5Authorizer(DummyAuthorizer):
    def validate_authentication(self, username, password, handler):
        hash = md5(password.encode('utf-8')).hexdigest()  # 与md5USerPassword.py上的算法一致
        try:
            if self.user_table[username]['pwd'] != hash:
                raise KeyError
        except KeyError:
            raise AuthenticationFailed

从文本文件加载用户信息

# 读取用户权限文件,向虚拟用户管理器添加用户
def add_user(authorizer):

    # 用户权限文件
    userfile = 'userMD5.txt'  # 文件格式如下(md5加密后的文件,运行md5UserPassword.py后自动生成)
    '''
        # 备注文字(用tab间隔开来)
        username    md5(password)    path    perm
        username    md5(password)    path    perm
        username    md5(password)    path    perm
    '''

    # 用户列表
    user_list = []
    split_str = '\t'

    # 从userMD5.txt读取用户信息
    with open(userfile) as f:
        for line in f:
            line = line.replace('\n', '')  # 去掉最后的\n
            if not line.startswith('#') and line:  # #后面是备注
                if len(line.split(split_str)) == 4:  # 用户名/密码/路径/权限
                    user_list.append(line.split(split_str))
                else:
                    print("userMD5.txt配置错误: %s" % line)

    # 添加用户
    for user in user_list:
        authorizer.add_user(user[0], user[1], './rootftp' + user[2], perm=user[3], msg_login="欢迎光临", msg_quit="欢迎下次光临")
        print('[%s\t---\t%s\t%s]' % (user[0], user[3], user[2]))

    # 返回虚拟用户管理器
    return authorizer

被动模式PASV

  • 如果有电脑在局域网中要连接外网的FTP, 则建议使用被动模式PASV进行连接
  • 设置一个假的IP地址, 确定一个被动模式端口的范围(默认设置为这个, 服务器的最后5000多个端口号)
# 被动模式配置
    # Specify a masquerade address and the range of ports to use for
    # passive connections.  Decomment in case you're behind a NAT.
    # 设置假IP地址发回给ftp客户端,设置被动模式的端口区间(最大65535)
    handler.masquerade_address = '151.25.42.11'  # ftp服务器的伪IP地址
    handler.passive_ports = range(60000, 65535)  # 被动模式下的随机端口

完整代码ftp.py

# coding:utf-8
from pyftpdlib.servers import FTPServer, MultiprocessFTPServer
from pyftpdlib.authorizers import DummyAuthorizer, AuthenticationFailed
from hashlib import md5
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.handlers import TLS_FTPHandler  # TLS_FTPHandler需要pip安装pyopenssl
from sys import argv  # 用来读取启动py文件时的命令行参数


# 是否启用ssl加密
USE_SSL = False  # 是否启用ftps加密传输,通过修改单独的文件设置,默认是不用ssl
if 'ssl' in argv:
    USE_SSL = True  # 如果要启用ssl,运行时要加参数 ssl
if 'mul' in argv:
    USE_MULTIPLE_PROCESS = True  # 开启多进程模式


# 验证用户密码hash后是否与原来的一样,照着官方文档写的,修改了一点
class DummyMD5Authorizer(DummyAuthorizer):
    def validate_authentication(self, username, password, handler):
        hash = md5(password.encode('utf-8')).hexdigest()  # 与md5USerPassword.py上的算法一致
        try:
            if self.user_table[username]['pwd'] != hash:
                raise KeyError
        except KeyError:
            raise AuthenticationFailed


# 读取用户权限文件,向虚拟用户管理器添加用户
def add_user(authorizer):

    # 用户权限文件
    userfile = 'userMD5.txt'  # 文件格式如下(md5加密后的文件,运行md5UserPassword.py后自动生成)
    '''
        # 备注文字(用tab间隔开来)
        username    md5(password)    path    perm
        username    md5(password)    path    perm
        username    md5(password)    path    perm
    '''

    # 用户列表
    user_list = []
    split_str = '\t'

    # 从userMD5.txt读取用户信息
    with open(userfile) as f:
        for line in f:
            line = line.replace('\n', '')  # 去掉最后的\n
            if not line.startswith('#') and line:  # #后面是备注
                if len(line.split(split_str)) == 4:  # 用户名/密码/路径/权限
                    user_list.append(line.split(split_str))
                else:
                    print("userMD5.txt配置错误: %s" % line)

    # 添加用户
    for user in user_list:
        authorizer.add_user(user[0], user[1], './rootftp' + user[2], perm=user[3], msg_login="欢迎光临", msg_quit="欢迎下次光临")
        print('[%s\t---\t%s\t%s]' % (user[0], user[3], user[2]))

    # 返回虚拟用户管理器
    return authorizer


#
def main():
    # 用户验证
    # Instantiate a dummy authorizer for managing 'virtual' users 创建虚拟用户管理器
    # authorizer = DummyAuthorizer()
    authorizer = DummyMD5Authorizer()  # 因为要验证hash值,所以改成这个了类了,官方写的, 这个类继承自DummyAuthorizer类

    # Define a new user having full r/w permissions and a read-only anonymous user
    # 读取userMD5.txt文件,绑定 用户-权限
    authorizer = add_user(authorizer)  # 写成了一个函数add_user()来自动读取userMD5.txt
    # authorizer.add_anonymous(os.getcwd())  # 匿名用户,关闭

    # ftp主控制器
    # Instantiate FTP handler class
    # 绑定FTP控制器
    if not USE_SSL:
        handler = FTPHandler  # ftp传输
    if USE_SSL:
        handler = TLS_FTPHandler  # ftps传输 = ftp + ssl
    handler.authorizer = authorizer  # 绑定用户管理器

    # ssl加密
    if USE_SSL:
        handler.certfile = 'crt_key.pem'  # 此处需要插入自签名证书文件base64编码的pem
        # requires SSL for both control and data channel
        # 启用ssl加密传输
        # handler.tls_control_required = True  # 控制连接启用ssl加密
        handler.tls_data_required = True  # 数据连接启用ssl加密

    # 锦上添花
    # Define a customized banner (string returned when client connects)
    # 定义ftp客户端[连接成功欢迎词]
    handler.banner = "欢迎你我尊贵的客人莅临指导"

    # 被动模式配置
    # Specify a masquerade address and the range of ports to use for
    # passive connections.  Decomment in case you're behind a NAT.
    # 设置假IP地址发回给ftp客户端,设置被动模式的端口区间(最大65535)
    handler.masquerade_address = '151.25.42.11'  # ftp服务器的伪IP地址
    handler.passive_ports = range(60000, 65535)  # 被动模式下的随机端口

    # ip限制及端口设定
    # Instantiate FTP server class and listen on 0.0.0.0:8081
    # 设置不限制IP地址访问,端口8081,使用TCP端口8081
    address = ('0.0.0.0', 8081)  # ip限制及连接端口(需要在安全组里放通这个端口)
    # 多进程模式是否开启
    if USE_MULTIPLE_PROCESS:
        server = MultiprocessFTPServer(address, handler)
    else:
        server = FTPServer(address, handler)

    # 最大连接数限制
    # set a limit for connections
    # 设置最大连接数,和相同IP地址的最大同时连接数
    server.max_cons = 50
    server.max_cons_per_ip = 20

    # 万事俱备,只欠东风
    # start ftp server
    # 启动ftp服务器
    server.serve_forever()


# 启动
if __name__ == '__main__':
    main()

启动

启动命令: python ftp.py ssl mul
后台运行: nohup python ftp.py >> log 2>&1 &

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352