10

我创建了一个程序,它遍历一堆文件并为其中一些文件调用:

scp <file> user@host:<remotefile>

但是,就我而言,可能有数千个小文件需要传输,并且 scp 正在为每个文件打开一个新的 ssh 连接,这会产生相当大的开销。

我想知道是否没有解决方案让我保持一个进程运行以维护连接,并且我可以向它发送“请求”以复制单个文件。

理想情况下,我正在寻找一些发送者和接收者程序的组合,这样我就可以在开始时启动一个进程 (1):

ssh user@host receiverprogram

对于每个文件,我调用一个命令 (2):

senderprogram <file> <remotefile>

并将 (2) 的输出通过管道传输到 (1) 的输入,这将导致文件被传输。最后,我可以发送进程 (1) 一些信号来终止。

优选地,发送者和接收者程序是用于Unix的开源C程序。他们可以使用套接字而不是管道或任何其他创造性的解决方案进行通信。

然而,每个文件在我迭代它的那一刻被传输是一个重要的限制scp:收集文件列表然后调用一个实例来一次传输所有文件是不可接受的。此外,我对接收主机只有简单的 shell 访问权限。

更新:我找到了使用 ssh 的多路复用功能解决连接开销问题的方法,请参阅下面我自己的答案。然而,我开始赏金,因为我很想知道是否存在我在这里描述的发送者/接收者程序。似乎应该存在可以使用的东西,例如xmodem/ymodem/zmodem?

4

14 回答 14

23

我从另一个角度找到了解决方案。从3.9 版本开始,OpenSSH 支持会话多路复用:单个连接可以承载多个登录或文件传输会话。这避免了每个连接的设置成本。

对于问题的情况,我可以首先打开一个连接,在特定位置设置一个-M带有套接字 () 的控制主机 () 。-S我不需要会话 ( -N)。

ssh user@host -M -S /tmp/%r@%h:%p -N

接下来,我可以scp为每个文件调用并指示它使用相同的套接字:

scp -o 'ControlPath /tmp/%r@%h:%p' <file> user@host:<remotefile>

此命令几乎立即开始复制!

您还可以将控制套接字用于正常的 ssh 连接,然后立即打开:

ssh user@host -S /tmp/%r@%h:%p

如果控制套接字不再可用(例如,因为您杀死了主控),这将回退到正常连接。本文提供了更多信息。

于 2009-02-06T07:20:46.987 回答
4

使用 sftp 而不是 scp 并将其置于批处理模式可能会起作用。使批处理命令文件成为管道或 UNIX 域套接字,并在您希望它们执行时将命令提供给它。

客户端的安全性可能有点棘手。

于 2009-02-05T12:38:37.487 回答
4

你试过sshfs吗?你可以:

sshfs remote_user@remote_host:/remote_dir /mnt/local_dir

在哪里

  • /remote_dir是您要发送文件到您正在进入的系统上的目录
  • /mnt/local_dir是本地安装位置

使用此设置,您只需cp将文件放入其中local_dir,然后将其发送sftpremote_hostremote_dir

请注意,只有一个连接,因此开销很小

您可能需要使用该标志-o ServerAliveInterval=15来维持无限期的连接

您将需要在fuse本地安装和支持(并配置)的 SSH 服务器sftp

于 2009-02-15T22:51:59.643 回答
4

这种方式可行,对于其他事情,这种通用方法或多或少是正确的。

(
iterate over file list
  for each matching file
   echo filename
) | cpio -H newc -o | ssh remotehost cd location \&\& | cpio -H newc -imud
于 2009-02-15T23:35:41.503 回答
3

也许你正在寻找这个: ZSSH

zssh (Zmodem SSH) 是一个程序,用于在使用安全外壳 (ssh) 时以交互方式将文件传输到远程机器。它旨在成为 scp 的便捷替代方案,允许传输文件而无需打开另一个会话并重新验证自己。

于 2009-02-12T22:54:00.207 回答
2

如果您可以收集所有文件以在单个目录(或目录层次结构)中发送,请使用 rsync over ssh。

如果您没有将所有文件放在一个地方,请提供更多信息,说明您想要实现的目标以及为什么不能将所有文件打包到存档中并将其发送出去。为什么立即发送每个文件如此重要?如果文件的发送延迟很短(比如累积了 4K 的数据),是否可以?

于 2009-02-05T16:38:50.623 回答
2

这是一个不错的小问题。我不知道预打包的解决方案,但您可以使用简单的 shell 脚本做很多事情。我会在接收器上试试这个:

#!/bin/ksh
# this is receiverprogram

while true
do
  typeset -i length
  read filename  # read filename sent by sender below
  read size      # read size of file sent
  read -N $size contents  # read all the bytes of the file
  print -n "$contents" > "$filename"
done

在发送方,我将创建一个命名管道并从管道中读取,例如,

mkfifo $HOME/my-connection
ssh remotehost receiver-script < $HOME/my-connection

然后发送文件我会尝试这个脚本

#!/bin/ksh
# this is senderprogram

FIFO=$HOME/my-connection

localname="$1"
remotename="$2"
print "$remotename" > $FIFO
size=$(stat -c %s "$localname")
print "$size" > $FIFO
cat "$localname" > $FIFO

如果文件很大,你可能不想一口气读完,所以大约是

BUFSIZ=8192

rm -f "$filename"
while ((size >= BUFSIZ)); do
  read -N $BUFSIZE buffer
  print -n "$buffer" >> "$filename"
  size=$((size - BUFSIZ))
done
read -N $size buffer
print -n "$contents" >> "$filename"

最终你会想要扩展脚本,这样你就可以通过chmodchgrp命令。由于您信任发送代码,因此构造事物可能是最简单的,以便接收者只需eval在每一行上调用 shell,然后发送类似

print filename='"'"$remotename"'"' > $FIFO
print "read_and_copy_bytes " '$filename' "$size" > $FIFO

然后定义一个局部函数read_and_copy_bytes。获得正确的报价是一件难事,但否则它应该是直截了当的。

当然,这些都没有经过测试!但我希望它能给你一些有用的想法。

于 2009-02-12T04:14:25.700 回答
1

似乎是 tar 的工作?将其输出通过管道传输到 ssh,在另一侧将 ssh 输出通过管道传输回 tar。

于 2009-02-05T12:37:55.413 回答
1

我认为 GNOME 桌面在通过 SFTP (SSH) 访问共享时使用单个 SSH 连接。我猜这是正在发生的事情,因为当我以这种方式访问​​远程共享时,我看到了一个 SSH 进程。因此,如果这是真的,您应该能够为此目的使用相同的程序。

新版本的 GNOME 通过GIO使用 GVFS ,以便通过不同的后端执行各种 I/O。Ubuntu 软件包 gvfs-bin 提供了各种命令行实用程序,可让您从命令行操作后端。

首先,您需要挂载 SSH 文件夹:

gvfs-mount sftp://user@host/

然后你可以使用 gvfs-copy 来复制你的文件。我认为所有文件传输都将通过单个 SSH 进程执行。您甚至可以使用 ps 查看正在使用的进程。

如果您觉得更有冒险精神,您甚至可以用 C 或其他为 GIO 提供 API 的高级语言编写自己的程序。

于 2009-02-11T10:39:43.477 回答
1

一种选择是Conch是使用Twsited框架用 Python 编写的 SSH 客户端和服务器实现。您可以使用它编写一个工具,该工具通过其他协议(HTTP 或 Unix 域套接字、FTP、SSH 或其他)接受请求,并通过长时间运行的 SSH 连接触发文件传输。事实上,我在生产中有几个程序使用这种技术来避免多个 SSH 连接设置。

于 2009-02-14T14:23:15.830 回答
1

几周前这里有一个非常相似的问题。接受的答案建议在 ssh'ing 到远程机器时打开一个隧道,并使用该隧道进行 scp 传输。

于 2009-02-16T19:59:42.483 回答
1

也许 CurlFTPFS可能是您的有效解决方案。

看起来它只是通过 SFTP 将外部计算机的文件夹安装到您的计算机上。完成后,您应该能够使用常规cp命令,并且一切都将安全地完成。

不幸的是,我无法自己测试它,但让我知道它是否适合你!

编辑1: 我已经能够下载并测试它。正如我担心的那样,它确实需要客户端有一个 FTP 服务器。 但是,我发现另一个程序与您正在寻找的概念完全相同。 sshfs允许您连接到您的客户端计算机,而无需任何特殊的服务器。安装其中一个文件夹后,您可以使用常规cp命令将所需的任何文件移动到更多位置。一旦你完成了,它应该是一个微笑的问题umount /path/to/mounted/folder。让我知道这是怎么回事!

于 2009-02-17T06:22:44.153 回答
0
rsync -avlzp user@remotemachine:/path/to/files /path/to/this/folder

这将使用 SSH 以非慢速方式传输文件

于 2009-02-12T04:17:29.500 回答
0

保持简单,写一个小包装脚本来做这样的事情。

  1. tar 文件
  2. 发送 tar 文件
  3. 在另一边解压

像这样的东西:

  1. tar -cvzf test.tgz 文件....
  2. scp test.tgz user@other.site.com:。
  3. ssh user@other.site.com tar -xzvf test.tgz

/约翰

于 2009-02-12T20:35:32.457 回答