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 &

你可能感兴趣的:(py-FTP服务器之四:ftp主程序)