Unix 发送方和接收方是否应请求通过ssh传输文件?

Unix 发送方和接收方是否应请求通过ssh传输文件?,unix,shell,ssh,sysadmin,file-transfer,Unix,Shell,Ssh,Sysadmin,File Transfer,我创建了一个程序,该程序迭代一组文件,并调用其中一些文件: scp <file> user@host:<remotefile> 对于每个文件,我调用一个命令(2): senderprogram 并将(2)的输出通过管道传输到(1)的输入,这将导致文件被传输。最后,我可以发送进程(1)一些终止信号 发送方和接收方程序最好是Unix的开源C程序。他们可以使用插座而不是管道或任何其他创造性的解决方案进行通信 但是,每个文件在我迭代时都会被传输,这是一个重要的约束条件:收集文

我创建了一个程序,该程序迭代一组文件,并调用其中一些文件:

scp <file> user@host:<remotefile>
对于每个文件,我调用一个命令(2):

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

发送方和接收方程序最好是Unix的开源C程序。他们可以使用插座而不是管道或任何其他创造性的解决方案进行通信

但是,每个文件在我迭代时都会被传输,这是一个重要的约束条件:收集文件列表,然后在最后调用
scp
的一个实例来传输所有文件是不可接受的。而且,我对接收主机只有简单的shell访问权限


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

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

使用sftp而不是scp,并将其置于批处理模式可能会起作用。将批处理命令文件设置为管道或UNIX域套接字,并根据需要将命令馈送到其中


这方面的安全性在客户端可能有点棘手。

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


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

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

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

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

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

如果控制插座不再可用(例如,因为您杀死了主机),则会恢复正常连接。更多信息可以在中找到。

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

新版本的GNOME通过使用GVFS来通过不同的后端执行所有类型的I/O。Ubuntu包gvfs-bin提供了各种命令行实用程序,允许您从命令行操作后端

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

gvfs安装sftp://user@主人/

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


如果你更喜欢冒险,你甚至可以用C或其他高级语言编写自己的程序,为GIO提供API。

这是一个很好的小问题。我不知道有一个预先打包的解决方案,但是你可以用简单的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
如果文件大小很大,您可能不希望一次读取它,因此

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"
最终,您将需要扩展脚本,以便可以传递
chmod
chgrp
命令。因为您信任发送代码,所以可能最简单的方法是构造内容,以便接收方只需在每一行上调用shell
eval
,然后发送如下内容

print filename='"'"$remotename"'"' > $FIFO
print "read_and_copy_bytes " '$filename' "$size" > $FIFO
然后定义一个本地函数
读取和复制字节
。获得正确的报价是一件困难的事,但除此之外,它应该是直截了当的

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

rsync -avlzp user@remotemachine:/path/to/files /path/to/this/folder

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

保持简单,编写一个小的包装器脚本来完成类似的操作

  • 给文件加焦油
  • 发送tar文件
  • 另一边的untar
  • 大概是这样的:

  • tar-cvzf test.tgz文件
  • scp-test.tgzuser@other.site.com:
  • sshuser@other.site.comtar-xzvf测试.tgz

  • /约翰

    也许你在找这个:

    zssh(zmodemsh)是一个在使用secureshell(SSH)的同时将文件交互传输到远程计算机的程序。它是scp的一种方便的替代方案,允许传输文件,而无需打开另一个会话并重新验证自己

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

    你试过了吗? 你可以:

    sshfs remote_user@remote_host:/remote_dir /mnt/local_dir
    
    在哪里

    • /remote\u dir
      是您要将文件发送到的系统上的目录
      #!/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"
      
      print filename='"'"$remotename"'"' > $FIFO
      print "read_and_copy_bytes " '$filename' "$size" > $FIFO
      
      rsync -avlzp user@remotemachine:/path/to/files /path/to/this/folder
      
      sshfs remote_user@remote_host:/remote_dir /mnt/local_dir
      
      (
      iterate over file list
        for each matching file
         echo filename
      ) | cpio -H newc -o | ssh remotehost cd location \&\& | cpio -H newc -imud