FTP协议
FTP 为什么还在用?一篇读懂它的工作原理
开篇:一个让你抓狂的场景
你写了一个 FTP 客户端,在公司内网测试一切正常。部署到客户环境后,文件传不成了——能登录,能列目录,但每次一传文件就卡死。
查了半天才发现:客户开了防火墙,而你的 FTP 用的是主动模式。
这就是 FTP 协议最让人头疼的地方:它用了两条独立的 TCP 连接,而这两条连接的建立方式还分两种模式。不搞清楚这一点,踩坑是迟早的事。
读完这篇文章,你会彻底理解 FTP 的双通道设计、主动/被动模式的区别,以及如何在实际项目中避坑。
TL;DR
- FTP 使用两条 TCP 连接:21 端口传命令(控制连接),数据端口传文件(数据连接)
- 主动模式:服务器主动连接客户端的数据端口 → 容易被客户端防火墙拦截
- 被动模式:客户端主动连接服务器的数据端口 → 对 NAT/防火墙更友好,现代网络首选
- 抓包时找不到数据传在哪?去看
PASV或PORT命令的响应,端口号藏在里面
一、什么是 FTP
FTP(File Transfer Protocol,文件传输协议)是 Internet 上最经典的文件传输协议,用于在主机间双向传输文件。
默认使用 TCP 的 20 和 21 两个端口:
| 端口 | 用途 |
|---|---|
| 21 | 控制连接 —— 发送命令和接收响应 |
| 20(或协商端口) | 数据连接 —— 传输文件内容 |
具体是否使用 20 端口作为数据端口,取决于 FTP 使用的传输模式:
- 主动模式:服务器数据端口默认使用 20
- 被动模式:端口由服务器和客户端协商决定
二、工作模式(核心章节)
FTP 支持两种工作模式:主动模式(PORT) 和 被动模式(PASV)。两者的控制连接建立过程完全一致,区别在于数据连接由谁发起。
2.1 一表看清区别
| 主动模式(PORT) | 被动模式(PASV) | |
|---|---|---|
| 数据连接发起方 | 服务器 → 客户端 | 客户端 → 服务器 |
| 服务器数据端口 | 默认 20 | 随机端口(协商决定) |
| 客户端数据端口 | 随机端口(客户端告知服务器) | 随机端口 |
| 防火墙友好度 | 差(客户端需开放入站端口) | 好(客户端发起出站连接) |
| 适用场景 | 无防火墙的内网 | 有 NAT/防火墙的互联网环境 |
| 标识命令 | PORT |
PASV |
2.2 被动模式流程(PASV)
文字步骤简述:
- 客户端随机端口 N(>1024)连接服务器 21 端口,建立控制连接
- 完成用户认证(USER / PASS)
- 客户端发送
PASV命令,服务器返回227响应,携带 IP 和端口号(port = p1×256 + p2) - 客户端用新随机端口连接服务器返回的数据端口,建立数据连接
- 数据传输完成后,数据连接关闭,控制连接保留
2.3 主动模式流程(PORT)
文字步骤简述:
- 控制连接建立和认证流程与被动模式相同
- 客户端通过控制连接发送
PORT命令,告知服务器自己的 IP 和监听端口 - 服务器从 20 端口主动向客户端指定端口发起数据连接
- 数据传输完成后,数据连接关闭
主动模式的核心问题:如果客户端在 NAT 或防火墙后面,服务器无法主动连入,数据传输就会失败。
三、数据传输
3.1 数据结构
FTP 支持三种文件结构(使用 STRU 命令指定):
| 结构 | 说明 |
|---|---|
| 文件结构(默认) | 文件被视为连续的字节流,无内部结构 |
| 记录结构 | 文件由连续记录组成,用于文本文件(TYPE ASCII / EBCDIC) |
| 页结构 | 用于不连续文件(如随机存取文件),每页传输附带页头信息 |
3.2 传输模式
| 模式 | 特点 | 文件结束标识 |
|---|---|---|
| 流模式 | 以字节流传输,最简单 | 关闭连接表示结束 |
| 块模式 | 数据以带头的块传输 | FTP 编码标识 |
| 压缩模式 | 支持数据压缩,有控制信息 | FTP 编码标识 |
流模式下传输多文件时,TCP 的 TIME_WAIT 可能导致端口无法立即复用。如果有多文件传输需求,可以考虑使用块模式或压缩模式,它们不需要关闭连接来标识文件结束。
3.3 数据连接管理要点
- 所有 FTP 实现必须支持默认数据端口,只有客户端可以使用非默认端口
- 客户端可通过
PORT命令指定非默认用户端口,也可通过PASV要求服务器指定非默认端口 - 服务器在以下情况会关闭数据连接:传输完成、收到 ABOR 命令、端口设定变更、控制连接关闭、不可恢复错误
四、FTP 命令速查
4.1 常用命令
| 命令 | 全称 | 用途 |
|---|---|---|
USER |
User | 用户名认证 |
PASS |
Password | 密码认证 |
PASV |
Passive | 进入被动模式 |
PORT |
Port | 指定主动模式的数据端口 |
RETR |
Retrieve | 下载文件 |
STOR |
Store | 上传文件 |
LIST |
List | 列出目录内容 |
CWD |
Change Working Directory | 切换工作目录 |
QUIT |
Quit | 断开连接 |
ABOR |
Abort | 中断当前传输 |
TYPE |
Type | 设置传输格式(A=ASCII, I=Binary) |
PWD |
Print Working Directory | 显示当前目录 |
4.2 完整命令参考
点击展开完整命令列表
访问控制命令:
| 命令 | 用途 |
|---|---|
USER |
用户名认证 |
PASS |
密码认证 |
ACCT |
账户信息(部分站点需要) |
CWD |
改变工作目录 |
CDUP |
返回上层目录 |
SMNT |
装载不同的文件系统结构 |
REIN |
重新初始化(保留控制连接,重置所有参数) |
QUIT |
注销并关闭控制连接 |
传输参数命令:
| 命令 | 用途 |
|---|---|
PORT |
指定主动模式数据端口 |
PASV |
请求被动模式 |
TYPE |
设置表示类型(ASCII / EBCDIC / Image / Local) |
STRU |
设置文件结构(File / Record / Page) |
MODE |
设置传输模式(Stream / Block / Compressed) |
服务命令:
| 命令 | 用途 |
|---|---|
RETR |
下载文件 |
STOR |
上传文件(覆盖) |
STOU |
唯一保存(不覆盖已有文件) |
APPE |
追加内容到文件末尾 |
ALLO |
预分配存储空间 |
REST |
断点续传标记 |
RNFR / RNTO |
重命名文件(从/到) |
ABOR |
放弃当前传输 |
DELE |
删除文件 |
RMD |
删除目录 |
MKD |
新建目录 |
PWD |
打印当前工作目录 |
LIST |
列出目录详细信息 |
NLST |
列出文件名列表 |
SITE |
站点特定服务 |
SYST |
获取服务器操作系统类型 |
STAT |
获取状态信息 |
HELP |
帮助 |
NOOP |
空操作(保活) |
五、FTP 响应码
FTP 响应码为三位数字,每位有特定含义:
第一位:状态类型
| 状态码 | 含义 | 说明 |
|---|---|---|
1xx |
预备状态 | 命令已接受,等待下一个命令 |
2xx |
完成状态 | 命令成功完成 |
3xx |
中间状态 | 命令已接受,等待进一步信息 |
4xx |
暂时拒绝 | 临时性错误,可重试 |
5xx |
永久拒绝 | 命令不被接受,不要重复请求 |
区分
4xx和5xx的规则:在相同状态下不加修改重复请求,是否还有可能成功。
第二位:响应类别
| 类别码 | 类别 | 含义 |
|---|---|---|
x0x |
语法 | 命令不存在、未实现或多余 |
x1x |
信息 | 对状态或帮助请求的响应 |
x2x |
连接 | 关于控制/数据连接的响应 |
x3x |
认证 | 登录过程和账户相关的响应 |
x4x |
未使用 | 保留 |
x5x |
文件系统 | 请求传输时的文件系统状态 |
常见响应码速查
| 码 | 含义 |
|---|---|
| 220 | 服务就绪 |
| 221 | 服务关闭控制连接 |
| 226 | 关闭数据连接,请求操作成功 |
| 227 | 进入被动模式(含 IP 和端口) |
| 230 | 用户登录成功 |
| 331 | 用户名 OK,需要密码 |
| 425 | 无法打开数据连接 |
| 426 | 连接关闭,传输中止 |
| 530 | 未登录 |
六、抓包实战分析
6.1 被动模式抓包
环境:服务器
192.168.106.9,客户端192.168.106.7
Step-by-step 分析:
| 步骤 | 方向 | 关键动作 | 关注点 |
|---|---|---|---|
| 1 | 客户端 → 服务器:21 | TCP 三次握手 | 控制连接建立 |
| 2 | 服务器:21 → 客户端 | 220 服务就绪 |
服务器已准备 |
| 3 | 客户端 → 服务器:21 | AUTH TLS / AUTH SSL |
鉴权尝试(非 SFTP 故跳过) |
| 4 | 客户端 → 服务器:21 | USER anonymous |
匿名登录 |
| 5 | 服务器:21 → 客户端 | 230 登录成功 |
|
| 6 | 客户端 → 服务器:21 | TYPE A |
设置为 ASCII 模式 |
| 7 | 服务器:21 → 客户端 | 200 设置成功 |
|
| 8 | 客户端 → 服务器:21 | PASV |
请求被动模式 |
| 9 | 服务器:21 → 客户端 | 227 Entering Passive Mode (192,168,106,9,4,15) |
端口 = 4×256+15 = 1039 |
| 10 | 客户端 → 服务器:1039 | TCP 三次握手 | 数据连接建立 |
| 11 | 客户端 → 服务器:21 | RETR 123test.txt |
请求下载文件 |
| 12 | 服务器:1039 → 客户端 | 文件数据 | 数据传输进行中 |
| 13 | 服务器:21 → 客户端 | 226 Transfer Complete |
传输完成,数据连接关闭 |
6.2 主动模式抓包
主动模式与被动模式的关键区别:在 PORT 命令中,客户端将自身 IP 和监听端口告知服务器,由服务器端 20 端口主动发起数据连接。如果客户端在防火墙/NAT 后面,这条入站 SYN 会被拦截——这就是主动模式最常见的故障原因。
七、常见踩坑与排错指南
坑 1:主动模式被防火墙拦截
| 项目 | 说明 |
|---|---|
| 现象 | 能登录、能列目录,但传输文件时卡住或超时 |
| 原因 | 客户端在 NAT/防火墙后面,服务器无法主动连接客户端的数据端口 |
| 根因 | 使用的是主动模式(PORT),数据连接方向是 服务器→客户端 |
| 解决 | 客户端改用被动模式(发送 PASV 而非 PORT) |
坑 2:被动模式端口范围未开放
| 项目 | 说明 |
|---|---|
| 现象 | 切换被动模式后仍失败,或部分文件传输失败 |
| 原因 | 服务器防火墙只开放了 21 端口,PASV 协商出的随机数据端口被拦截 |
| 解决 | 在服务器端配置 PASV 端口范围(如 pasv_min_port=30000, pasv_max_port=30100),并在防火墙放行该范围 |
坑 3:FTP over TLS 被防火墙静默丢包
| 项目 | 说明 |
|---|---|
| 现象 | 明文 FTP 正常,启用 FTPS(FTP over TLS)后无法传输 |
| 原因 | 防火墙/IPS 对加密 FTP 控制连接做深度包检测失败,直接丢包或中断连接 |
| 解决 | 尝试将控制连接端口从 21 改为非标准端口;或确认防火墙支持 FTPS 并已配置放行 |
排错 Checklist
写在最后
FTP 诞生于 1971 年,早于 TCP/IP 协议栈,也早于防火墙和 NAT 这些现代网络基础设施。它的双通道设计在当年是优雅的,在今天就变成了麻烦。
但只要理解了主动/被动模式这一核心概念,FTP 依然是简单可靠的。下次遇到 FTP 问题,记得先问自己一个问题:数据连接是谁连谁?
作者:北小北
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。

浙公网安备 33010602011771号