基础知识

FTP只通过TCP连接,FTP不同于其他服务的是它使用了两个端口, 一个数据端口和一个命令端口(或称为控制端口)。

通常21端口是命令端口,20端口是数据端口。当混入主动/被动模式的概念时,数据端口就有可能不是20了

FTP主动模式

在主动模式下,FTP客户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,

然后开放N+1号端口进行监听,并向服务器发出PORT N+1命令。

服务器接收到命令后,会用其本地的FTP数据端口(通常是20)来连接客户端指定的端口N+1,进行数据传输。

  • FTP服务器命令(21)端口接受客户端任意端口(客户端初始连接)
  • FTP服务器命令(21)端口到客户端端口(>1023)(服务器响应客户端命令)
  • FTP服务器数据(20)端口到客户端端口(>1023)(服务器初始化数据连接到客户端数据端口)
  • FTP服务器数据(20)端口接受客户端端口(>1023)(客户端发送ACK包到服务器的数据端口)

主动模式的优点:

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

主动模式的缺点:

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

FTP被动模式

在被动模式下,FTP库户端随机开启一个大于1024的端口N向服务器的21号端口发起连接,同时会开启N+1号端口。

然后向服务器发送PASV命令,通知服务器自己处于被动模式。

服务器收到命令后,会开放一个大于1024的端口P进行监听,然后用PORT P命令通知客户端,自己的数据端口是P。

客户端收到命令后,会通过N+1号端口连接服务器的端口P,然后在两个端口之间进行数据传输

  • FTP服务器命令(21)端口接受客户端任意端口(客户端初始连接)
  • FTP服务器命令(21)端口到客户端端口(>1023)(服务器响应客户端命令)
  • FTP服务器数据端口(>1023)接受客户端端口(>1023)(客户端初始化数据连接到服务器指定的任意端口)
  • FTP服务器数据端口(>1023)到客户端端口(>1023)(服务器发送ACK响应和数据到客户端的数据端口)

被动模式缺点:

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

被动模式的优点:

对客户端网络环境没有要求

使用python来实现FTP服务

安装模块 pyftpdlib

pip3 install pyftpdlib

http://pyftpdlib.readthedocs.io/en/latest/tutorial.html教程

源码

https://github.com/giampaolo/pyftpdlib

使用:

from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer# 新建一个用户组
authorizer = DummyAuthorizer()
# 将用户名,密码,指定目录,权限 添加到里面
authorizer.add_user("fan", "root", "E:/", perm="elr")  # adfmw
# 这个是添加匿名用户,任何人都可以访问,如果去掉的话,需要输入用户名和密码,可以自己尝试
authorizer.add_anonymous("E:/")handler = FTPHandler
handler.authorizer = authorizer
# 开启服务器
server = FTPServer(("127.0.0.1", 21), handler)
server.serve_forever()

然后将程序运行起来,接下来看一下效果,在浏览器上ftp://localhost/

用户权限

读取权限:

"e" =更改目录(CWD,CDUP命令)

"l" =列表文件(LIST,NLST,STAT,MLSD,MLST,SIZE命令)

"r" =从服务器检索文件(RETR命令)

写入权限:

"a" =将数据追加到现有文件(APPE命令)

"d" =删除文件或目录(DELE,RMD命令)

"f" =重命名文件或目录(RNFR,RNTO命令)

"m" =创建目录(MKD命令)

"w" =将文件存储到服务器(STOR,STOU命令)

"M"=更改文件模式/权限(SITE CHMOD命令)

"T"=更改文件修改时间(SITE MFMT命令)

开启被动端口模式

#添加被动端口范围
handler.passive_ports = range(8300, 8500)
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer# 新建一个用户组
authorizer = DummyAuthorizer()
# 将用户名,密码,指定目录,权限 添加到里面
authorizer.add_user("test", "1234", "E:/", perm="elradfmw")  # adfmw
# 这个是添加匿名用户,任何人都可以访问,如果去掉的话,需要输入用户名和密码,可以自己尝试
authorizer.add_anonymous("E:/")handler = FTPHandler
handler.authorizer = authorizer#添加被动端口范围
handler.passive_ports = range(8300, 8500)# 开启服务器
server = FTPServer(("127.0.0.1", 2121), handler)
server.serve_forever()-----------输出-----------------[I 2018-08-06 15:37:16] >>> starting FTP server on 127.0.0.1:2121, pid=8564 <<<
[I 2018-08-06 15:37:16] concurrency model: async
[I 2018-08-06 15:37:16] masquerade (NAT) address: None
[I 2018-08-06 15:37:16] passive ports: 8300->8499
[I 2018-08-06 15:37:32] 127.0.0.1:54898-[] FTP session opened (connect)

读取用户列表,建立FTP

#-----------user.ini------[alex]
password=123
perm=elradfmwM
home=D:/[egon]
password=123456
perm=elradfmwM
home=D:/#------------ftpdemofrom pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler, ThrottledDTPHandler
from pyftpdlib.servers import FTPServer
import configparser
import loggingIP = '127.0.0.1'PORT = '2121'# 上传速度  100kb/s
MAX_UPLOAD = 100 * 1024# 下载速度 100kb/s
MAX_DOWNLOAD = 100 * 1024# 最大连接数
MAX_CONS = 100# 最多IP数
MAX_PER_IP = 10# 被动端口范围,注意被动端口数量要比最大IP数多,否则可能出现无法连接的情况
PASSIVE_PORTS = (8300, 8500)# 是否开启匿名访问 on|off
ENABLE_ANONYMOUS = 'off'# 匿名用户目录
ANONYMOUS_PATH = 'E:/DEVTOOL/'# 日志文件
LOGING_NAME = 'pyftp.log'# 欢迎信息
WELCOME_MSG = 'Welcome to my ftp'# 新建一个用户组
authorizer = DummyAuthorizer()# 读取用户配置
config = configparser.ConfigParser()
config.read('user.ini')
user_list = config.sections()
for user in user_list:passwd = config[user]["password"]perm = config[user]["perm"]home_dir = config[user]["home"]# 将用户名,密码,指定目录,权限 添加到里面authorizer.add_user(user, passwd, homedir=home_dir, perm=perm)# 添加匿名用户 只需要路径
if ENABLE_ANONYMOUS == 'on':authorizer.add_anonymous(ANONYMOUS_PATH)# 下载上传速度设置
dtp_handler = ThrottledDTPHandler
dtp_handler.read_limit = MAX_DOWNLOAD
dtp_handler.write_limit = MAX_UPLOAD# 初始化ftp句柄
handler = FTPHandler
handler.authorizer = authorizer# 添加被动端口范围
handler.passive_ports = range(PASSIVE_PORTS[0], PASSIVE_PORTS[1])# 欢迎信息
handler.banner = WELCOME_MSG# 监听ip 和 端口
server = FTPServer((IP, PORT), handler)# 最大连接数
server.max_cons = MAX_CONS
server.max_cons_per_ip = MAX_PER_IP# 开始服务
print('FTP开始服务 ', (IP, PORT))
server.serve_forever()

基于twisted

#!/usr/bin/env python
# -*- coding: utf-8 -*-  """a very simple ftp server by twisted
"""  __author__ = "Bobning(nb5550606@gmail.com)"  import sys, os
sys.path.append('../../..')
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'  from twisted.protocols import ftp
from twisted.cred import portal, checkers, credentials, error as credError
from twisted.internet import reactor, defer
from zope.interface import implements
from twisted.python import filepath
from django.contrib.auth import authenticate
from django.contrib.auth.models import User  class UserChecker:  implements(checkers.ICredentialsChecker)  credentialInterfaces = (credentials.IUsernamePassword,)  def __init__(self):  "passwords: a dict-like object mapping usernames to passwords"  def requestAvatarId(self, credentials):  user = authenticate(username=credentials.username, password=credentials.password)  if user is not None:  if user.is_active:  return defer.succeed(credentials.username)  else:  return defer.fail(credError.UnauthorizedLogin("access denied"))  else:  return defer.fail(credError.UnauthorizedLogin("No such user"))  class MyFTPRealm:  implements(portal.IRealm)  def __init__(self, anonymousRoot):  self.anonymousRoot = filepath.FilePath(anonymousRoot)  def requestAvatar(self, avatarId, mind, *interfaces):  for iface in interfaces:  if iface is ftp.IFTPShell:  if avatarId is checkers.ANONYMOUS:  avatar = ftp.FTPAnonymousShell(self.anonymousRoot)  else:  try:  user = User.objects.get(username=avatarId)  ftpdir = user.ftp.all()[0].ftpdir  except:  raise "没有该用户"  avatar = ftp.FTPShell(filepath.FilePath(ftpdir.encode("utf-8")))  return ftp.IFTPShell, avatar, getattr(avatar, "logout", lambda:None)  raise NotImplementedError("only IFTPShell interface is supported by this realm")  class MyFtpServer(ftp.FTP):  def __init__(self, *args, **kw):  super(ftp.FTP, self).__init__(*args, **kw)  def dataReceived(self, data):  self.transport.write(data)  if __name__ == "__main__":  p = portal.Portal(MyFTPRealm(""))  p.registerChecker(UserChecker())  factory = ftp.FTPFactory(MyFtpServer())  factory.portal = p  reactor.listenTCP(2121, factory)  reactor.run()  

客户端实现

import ftplib
import sys#获取服务器的ip地址(如192.168.1.107),使用sys.argv可以从命令行参数里面获取
if len(sys.argv) < 2:tmp = input("please input server address:")sys.argv.append(tmp)
server_address = sys.argv[1]
#创建FTP实例,并显示欢迎界面
ftp = ftplib.FTP(server_address)
print(ftp.getwelcome())
#登录,输入服务器里添加过的用户名和口令
ftp.login('user', 'pass')#文件上传
def upload(fname):fd = open(fname, 'rb')new_name = input("input new name:")#以二进制的形式上传ftp.storbinary("STOR %s" % new_name, fd)fd.close()print("upload finished")#文件下载
def download(fname):#构建文件的存储路径,这里用的是D盘,可以自行设置new_path = "D:\\FTPdownload\\" + fnamefd = open(new_path, 'wb')#以二进制形式下载,注意第二个参数是fd.write,上传时是fdftp.retrbinary("RETR %s" % fname, fd.write)fd.close()print("download finished")def main():#选择操作,上传、下载、退出op = input("what do you want?(u/d/q)")if op == "u":#输入文件完整路径,必要时可以用绝对路径fname = input("input the file of path:")upload(fname)elif op == "d":fname = input("input the file name:")download(fname)else:print("quit now!")ftp.quit()if __name__ == '__main__':main()

附带一些ftplib库的相关操作:

ftp.cwd(pathname)           # 设置FTP当前操作的路径
ftp.dir()                   # 显示目录下所有目录的信息
ftp.nlst()                  # 获取目录下的文件
ftp.mkd(pathname)           # 新建远程目录
ftp.rmd(dirname)            # 删除远程目录
ftp.pwd()                   # 返回当前所在位置
ftp.delete(filename)        # 删除远程文件
ftp.rename(old_name, new_name)    #将fromname改为toname
ftp.storbinary('STOR filename.txt',file_handel,[bufsize])  # 上传目标文件,最后一个参数可以不填
ftp。retrbinary('RETR filename.txt',file_handel,[bufsize])  # 下载FTP文件

Python实现FTP服务器和客户端相关推荐

  1. python --搭建FTP服务器

    一.了解FTP服务器 二.利用python搭建FTP服务器 1.安装 pyftpdlib 模块 2.找到pyftpdlib模块源文件所在目录 3.到 pyftpdlib目录下 4. 编写并运行FTP代 ...

  2. 思维导图 - 测试技术扩展:Postman接口测试、Sonar白盒测试、Sonic移动测试、Python操作FTP服务器

    给大家整理了下测试技术扩展相关的学习文档. 第一章: Postman 接口测试工具 测试工具 - Postman 接口测试入门使用手册,Postman 如何进行数据关联.自动更新 cookies.简单 ...

  3. Python 连接FTP服务器并实现文件夹下载实例演示,python区分ftp目录下文件和文件夹方法,ftp目录下包含中文名问题处理

    Python 连接 FTP 服务器并实现文件夹下载实例演示 第一章:连接 FTP 服务器并实现文件夹下载 ① 连接 FTP 服务器 ② 进入指定目录并显示文件信息 ③ 区分文件和文件夹名 ④ 文件夹名 ...

  4. Python操作FTP服务器实现文件和文件夹的上传与下载,python清理ftp目录下的所有文件和非空文件夹

    Python 连接 FTP 服务器并实现文件夹上传实例演示 第一章:连接 FTP 服务器并实现文件夹上传 ① 连接 FTP 服务器 ② 区分文件和文件夹名 ③ 文件夹名包含空格处理 ④ 使用递归实现: ...

  5. FTP服务器和客户端

    <计算机通信网络>课程项目 终期报告 题 目: FTP协议实现 组 号: 第7组 任课教师: 王瑞 FT 2019年03月01日 FTP协议实现 一.项目介绍 文件传输协议(File Tr ...

  6. Python 连接 ftp 服务器操作

    Python 连接 ftp 服务器操作 1. 连接 ftp 服务器 2. 基本命令 1. 连接 ftp 服务器 代码如下 # !/usr/bin/python # -*- coding: utf-8 ...

  7. Linux FTP服务器与客户端(FTP命令 C/C++代码实现)

    FTP 是 TCP/IP 提供的标准互联网协议,用于将文件从一台主机传输到另一台主机.它主要用于将网页文件从其创建者传输到充当 Internet 上其他计算机的服务器的计算机.它还用于将文件从其他服务 ...

  8. python远程ftp服务器文件,如何将远程python FTP服务器连接到本地pythonftp客户端

    我正在使用pythonftp服务器和客户端程序.我需要的是在与本地计算机连接在同一网络上的远程计算机上运行pythonftp服务器.FTP客户端将从本地计算机运行,我需要将FTP服务器与运行在本地计算 ...

  9. python 搭建ftp服务器

    代码示例: # coding: utf-8 import os from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.han ...

最新文章

  1. 在sae上编译代码是所遇到的问题
  2. java list 删除 遍历_Java list利用遍历进行删除操作3种方法解析
  3. 高性能MySQL读书笔记---查询优化
  4. PHP中Header函数和PHP_AUTH_USER做用户验证
  5. Wannafly挑战赛18C 异或和
  6. Android官方导航栏ActionBar(二)—— Action View、Action Provider、Navigation Tabs的详细用法...
  7. CentOS查看和修改PATH环境变量的方法
  8. me shy是什么歌 抖音make_内含活动福利 | 小红书、抖音爆赞的高颜值的北欧家居神店开到卜蜂中心啦!...
  9. 联想x250为什么这么贵_外媒:联想笔记本thinkpadX250如何联想thinkpadX250价格及评价...
  10. 内核开发知识第二讲,编写Kerner 程序中注意的问题.
  11. opencv的android.mk,android-opencv 版本下JNI Android.mk文件的书写
  12. Akka创建第一个Actor《nine》译
  13. springboot+vue+easychart报表导出前后台
  14. 互联网数据响应时间计算公式
  15. c语言flag什么意思,立flag是什么意思flag是什么?立flag用语出处和使用方法
  16. Typora怎么插入图片链接,并设置图片居中
  17. python七段数码管显示字母代码_python实现七段数码管显示
  18. 网络存储技术Windows server 2012(项目三 存储池的配置与管理)
  19. 立冬、小雪、凛冬将至:如何理解美国科技企业裁员潮?
  20. 什么是百度转码?如何禁止网站百度转码?

热门文章

  1. 那个一年发四篇Cell的研究生,后来怎么样了?
  2. 哈佛大学单细胞课程|笔记汇总 (七)
  3. 如何使用Bioconductor进行单细胞分析?
  4. MacOSX系统怎么开启Root账户?Mac电脑开启root权限教程
  5. STM32+CubeMX开发工程笔记汇总(更新2021.8.12)
  6. Vue第三部分(1):Vue脚手架构建过程详细介绍和案例
  7. Git 实用命令项目基操【合集】
  8. python脚本如何编译_如何编译用于FORTRAN的Python脚本?
  9. Spring Boot通过url设置国际化
  10. Qt工作笔记-动态折线图(x轴坐标会改变)