这个客户端不会实用价值,之所以写它,是因为可以
- 了解 FTP 协议
- 熟悉 Emacs Lisp 网络编程
FTP 客户端连上 FTP 服务器,建立一个持续连接,客户端发送命令,服务器返回结果。当客户端请求上传、下载和 LIST 等时,临时建立一个专门传输该数据的连接,该连接随后即关闭。这两种连接叫做:
- control connection
- data connection
建立 data connection 有两种方法:
- 由服务器发起,客户端先告诉服务器「我的 1234 端口可用,你来连啊」
- 由客户端发起,服务器先告诉客户端「我的 5678 端口可用,你来连啊」
这两种方法分别叫做:
- active mode
- passive mode
这里「主动」和「被动」的主语显然是客户端。
FTP 协议一开始只有 active mode,但是由于 NAT、防火墙,客户端无法接收 「incoming TCP connections」,这时只能用 passive mode。
- Firewall (computing) - Wikipedia
- 可能需要了解 TCP 协议,特别是 TCP 连接建立、数据传输、关闭
搞清楚:
比如 curl example.com 时,服务器返回 HTML,透过 NAT、防火墙,我也肯定能收到。但是假如 example.com 每 5 秒就主动向我的电脑的 8888 端口发送 HTML,即使我在监听这个端口,我也接受不到 HTML?!因为 NAT 应该压根就不知道把数据传给谁,对不对?
客户端向服务器发送「FTP commands」,服务器向客户端返回「FTP reply codes」。
FTP command | 作用 |
---|---|
USER | 用户名 |
PASS | 密码 |
CWD | 改变目录 |
LIST | 显示目录内容* |
RETR | 下载一个文件* |
STOR | 上传一个文件* |
PASV | passive 模式 |
EPSV | Extended Passive 模式 |
=*= 表示需要 data connections
List of FTP server return codes - Wikipedia
看看 FTP 客户端的工作流程,先用 ftp 命令行,再用 netcat 手写 FTP commands 和 解析 FTp reply codes。
目标都是下载 ftp://mirrors.ustc.edu.cn/vim/README
Mac 上没有 ftp 命令,先安装 GNU inetutils
brew install inetutils
开始
~ $ ftp -d mirrors.ustc.edu.cn Connected to mirrors.ustc.edu.cn. 220 (vsFTPd 3.0.3) Name (mirrors.ustc.edu.cn:xcy): anonymous ---> USER anonymous 331 Please specify the password. Password: ---> PASS XXXX 230 Login successful. ftp> passive Passive mode on. ftp> epsv Use of EPRT/EPSV for IPv4: on. ftp> get vim/README vim.README ---> EPSV 229 Entering Extended Passive Mode (|||50180|) ---> RETR vim/README 150 Opening BINARY mode data connection for vim/README (7752 bytes). WARNING! 180 bare linefeeds received in ASCII mode File may -not have transferred correctly. 226 Transfer complete. 7752 bytes received in 0.00992 seconds (763 kbytes/s) ftp> quit ---> QUIT 221 Goodbye.
-d
开启 debug,这样会打印所发送的 FTP commands- 中科大镜像的 FTP 支持 anonymous,用户名就是 anonymous,不要密码(随便填一个,空的也行,还可以填自己邮箱,告诉服务器你是谁)
- Active Mode 我这边(中国电信)其实可以用,但是我还是用 passive 和 epsv 切换到了 Extended Passive Mode,光 epsv 好像不行,应该是 ftp 命令行的问题
get vim/README vim.README
下载 vim/README 到本地的 vim.READMEquit
退出
ftp 会用到两个连接,所以需要用两次 netcat 命令。
登陆:
~ $ nc mirrors.ustc.edu.cn 21 220 (vsFTPd 3.0.3) USER anonymous 331 Please specify the password. PASS xuchunyang 230 Login successful.
进入 extended passive mode
EPSV 229 Entering Extended Passive Mode (|||50191|)
注意 (|||50191|) 中的数字就是服务器要我们连接的端口。打开另一个终端,读取数据
~ $ nc mirrors.ustc.edu.cn 50160
在第一个 netcat 中,下载文件
RETR vim/README
在第二个 netcat 中,会查看到
~ $ nc mirrors.ustc.edu.cn 50160 README file for Vim - Vi IMproved --------------------------------- Vim is an almost 100% compatible version of the UNIX editor Vi. Many new features have been added: Multi level undo, syntax highlighting, command line ... ...
(setq
proc
(make-network-process
:name "ftp"
:buffer "ftp"
:host "mirrors.ustc.edu.cn"
:service 21))
;; => #<process ftp>
(process-send-string proc "USER anonymous\n")
;; => nil
(process-send-string proc "PASS\n")
;; => nil
(process-send-string proc "EPSV\n")
;; => nil
(setq
data-proc
(make-network-process
:name "ftp-data"
:buffer "ftp-data"
:host "mirrors.ustc.edu.cn"
:service 50157))
;; => #<process ftp-data>
(process-send-string proc "RETR vim/README\n")
;; => nil
(process-send-string proc "help\n")
;; => nil
(process-send-string proc "quit\n")
;; => nil
ftp(1) 就是一个 REPL,Emacs 有很多这类应用
- comint
- eshell
- ielm
- shell
但我不了解怎么实现的,先就这样吧。