我正在阅读一些通过 SSH 客户端发送文件的 Go 代码。
https://github.com/tmc/scp/blob/master/scp.go#L33
它所做的事情之一是scp -t /remote/path
.那面旗帜是做什么-t
用的?我做了一个man scp
,但似乎没有记录。我在本地运行了该命令,它的行为似乎像 cat。
远程运行后scp -t
,代码会像这样将字节发送到服务器。
// Some special control header? What is this?
fmt.Fprintf(w, "C%#o %d %s\n", mode, size, fileName)
// Send file bytes.
io.Copy(w, contents)
// Send termination signal?
fmt.Fprint(w, "\x00")
这个协议是什么?它在任何地方都有记录吗?
答案1
AFAIK,除了源代码之外,scp 协议没有记录在其他任何地方scp.c
,因此这里尝试概述一下scp
工作原理。
当源或目标是远程计算机时,scp
将用于ssh
连接并启动scp
其上的程序:如果复制方向是从远程到本地,则它将启动为scp -f src
(来自/来源),否则将以scp -t dst
(下沉),而本地人scp
会采取相反的姿势。
此后,两个 scp 进程在 scp 连接的两端运行,将其用作标准输入/标准输出,并通过其传递文件数据和元数据。
两端都可以使用以下响应来确认消息或发出某些错误情况信号:
"\0"
: 好的"\1%s\n", err_msg
:非致命错误"\2%s\n", err_msg
: 致命错误
传输开始于到/接收 scp发送一个\0
(OK)确认。
然后来自/来源 scp将使用以下消息:
"C%04o %lld %s\n", mode, size, filename
:创建一个文件接下来是
size
文件数据字节和 ack (\0
= OK)"D%04o 0 %.1024s\n", mode, dirname
: 目录开始递归地跟随
C
,D
或T
消息,直到"E\n"
: 目录结束"T%llu 0 %llu 0\n", mtime, atime
: 文件时间如果使用了开关,则在
C
或D
消息之前发送该消息。-p
这些消息在进一步处理之前必须得到对方的确认,包括C
发送文件数据之前的确认,以及发送文件数据之后发送的确认。
在上面的C
和D
消息中,文件/目录名称中的换行符和其他控制字符(除了\t
和\x7f
)将被转义,例如。\^J
,但会不是到达目的地后未逃脱;文字\^J
或\^M
原始名称将保持原样。
致命错误和非致命错误的区别并不一致;任何\1
一方都会生成(非致命)错误,但其中一些错误将被视为致命错误,并且scp
将在发送或接收错误时退出,让另一方保留这两部分。双方都会因\2
(致命)错误或任何意外情况而退出。
与 http 不同,没有规定按块发送文件数据;如果源scp
不再能够读取在消息之后开始发送的某些大文件,它将在错误消息/nak之前C
发送最多size
NUL 字节。\1