Skip to content

Latest commit

 

History

History
208 lines (151 loc) · 5.63 KB

ftp.org

File metadata and controls

208 lines (151 loc) · 5.63 KB

试试用 Emacs Lisp 写个 FTP 客户端

这个客户端不会实用价值,之所以写它,是因为可以

  • 了解 FTP 协议
  • 熟悉 Emacs Lisp 网络编程

FTP 客户端是如何工作的?

两种连接

FTP 客户端连上 FTP 服务器,建立一个持续连接,客户端发送命令,服务器返回结果。当客户端请求上传、下载和 LIST 等时,临时建立一个专门传输该数据的连接,该连接随后即关闭。这两种连接叫做:

  1. control connection
  2. data connection

两种模式

建立 data connection 有两种方法:

  • 由服务器发起,客户端先告诉服务器「我的 1234 端口可用,你来连啊」
  • 由客户端发起,服务器先告诉客户端「我的 5678 端口可用,你来连啊」

这两种方法分别叫做:

  1. active mode
  2. passive mode

这里「主动」和「被动」的主语显然是客户端。

FTP 协议一开始只有 active mode,但是由于 NAT、防火墙,客户端无法接收 「incoming TCP connections」,这时只能用 passive mode。

了解 NAT 或防火墙是如何区别客户需要的连接和其它的

搞清楚:

比如 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上传一个文件*
PASVpassive 模式
EPSVExtended 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

用 ftp 命令行程序

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.
  1. -d 开启 debug,这样会打印所发送的 FTP commands
  2. 中科大镜像的 FTP 支持 anonymous,用户名就是 anonymous,不要密码(随便填一个,空的也行,还可以填自己邮箱,告诉服务器你是谁)
  3. Active Mode 我这边(中国电信)其实可以用,但是我还是用 passive 和 epsv 切换到了 Extended Passive Mode,光 epsv 好像不行,应该是 ftp 命令行的问题
  4. get vim/README vim.README 下载 vim/README 到本地的 vim.README
  5. quit 退出

用 netcat 手写 FTP commands

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
...
...

Emacs Lisp 实现

(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

但我不了解怎么实现的,先就这样吧。