FTP 是最古老的文件传输协议之一,也是最“怪”的:一条控制连接发命令,每次传输再另开一条数据连接,还分主动和被动两种方向。这篇在本机起一个 FTP 服务器,逐个把这些怪处看清楚,并量出它为什么不适合传一大堆小文件。
S: 220 w99 test ftp ready
C: USER alice
S: 331 Username ok, send password.
C: PASS pa55w0rd
S: 230 Login successful.
C: SYST
S: 215 UNIX Type: L8
C: FEAT
S: 211-Features supported:
S: EPRT
S: EPSV
S: MDTM
S: MFMT
S: MLST type*;perm*;size*;modify*;unique*;unix.mode;unix.uid;unix.gid;
S: REST STREAM
S: SIZE
S: TVFS
S: UTF8
S: 211 End FEAT.
C: PWD
S: 257 "/" is the current directory.
C: CWD pub
S: 250 "/pub" is the current directory.
C: PWD
S: 257 "/pub" is the current directory.
C: TYPE I
S: 200 Type set to: Binary.
C: SIZE f0.txt
S: 213 700
C: QUIT
S: 221 Goodbye.
注意 PASS 命令把密码 pa55w0rd 明文写在控制连接上(下面第四节抓包验证);FEAT 的多行答复用 “211-” 开头、“211 ” 结尾,和 SMTP 的 250- 一样文本命令与三位数字答复,多行答复用 “211-” 到 “211 ”,和 SMTP 同一种风格。
S: 230 Login successful.
C: CWD pub
S: 250 "/pub" is the current directory.
C: TYPE I
S: 200 Type set to: Binary.
C: PASV
S: 227 Entering passive mode (127,0,0,1,37,8).
*: 227 里的 (127,0,0,1,37,8) → 端口 = 37 × 256 + 8 = 9480
*: 客户端另开一条 TCP 连接 127.0.0.1:9480 → 127.0.0.1:9480(数据连接)
C: LIST
S: 125 Data connection already open. Transfer starting.
*: 数据连接上收到 694 字节(目录列表),服务器发完就关闭这条连接:'-rw-r--r-- 1 w staff 200000 Oct 15 11:10 big.bin' …
S: 226 Transfer complete.
C: QUIT
S: 221 Goodbye.PASV 报告端口,客户端再连;数据连接用完即关。
C: EPSV
S: 229 Entering extended passive mode (|||9466|).
C: QUIT
S: 221 Goodbye.
PORT 127,0,0,1,228,126(= 端口 228 × 256 + 126 = 58494)→ 服务器答复 '200 Active data connection established.';随后 LIST 时,**服务器**主动连客户端的 58494 端口:数据连接的服务器一侧端口是 58496,方向与被动模式相反;收到 694 字节的目录列表,控制连接答复 '125 Data connection already open. Transfer starting.'
被动模式里数据连接由客户端发起(穿 NAT 友好);主动模式由服务器发起,客户端在 NAT 后面就收不到——这是 FTP 在现代网络里首选被动模式的原因主动模式 PORT 让服务器反过来连客户端;EPSV 只给端口,支持 IPv6。
控制连接的全部字节(241 字节)里能直接读到:USER alice; PASS pa55w0rd; CWD pub; RETR f0.txt 所以 FTP 的密码在路径上任何一个能抓包的地方都能被读走;FTPS(FTP over TLS)和 SFTP(基于 SSH,不是 FTP)是后来补的
用户名、密码、文件名全是明文。
登录(TCP 握手 + 220 + USER + PASS + CWD + TYPE)中位 608 ms ≈ 6.1 个往返;取 10 个小文件 中位 4051 ms,平均每个 405 ms ≈ 4.1 个往返(PASV 1 个、连数据端口 1 个、RETR 1 个,外加传输收尾) 取一个 200000 字节的大文件:505 ms 对比 HTTP/1.1 keep-alive:取一个小文件只要 1 个往返;FTP 小文件每个要约 4 个往返,所以 FTP 不适合大量小文件
每个文件一条新数据连接,小文件约 4.1 个往返;登录约 6.1 个往返。