Отправитель и получатель для передачи файлов по ssh по запросу?


Я создал программу, которая перебирает кучу файлов и вызывает для некоторых из них:

scp <file> user@host:<remotefile>
Однако в моем случае могут существовать тысячи небольших файлов, которые необходимо перенести, и scp открывает новое ssh-соединение для каждого из них, что имеет довольно большие накладные расходы.

Мне было интересно, нет ли решения, где я держу один запущенный процесс, который поддерживает соединение, и я могу отправлять ему "запросы" на копирование по отдельным файлам.

В идеале, я ищу комбинация некоторой программы отправителя и получателя, так что я могу запустить один процесс (1) в начале:

ssh user@host receiverprogram

И для каждого файла я вызываю команду (2):

senderprogram <file> <remotefile>

И соедините выходные данные (2) с входными данными (1), и это приведет к передаче файла. В конце концов, я могу просто послать процессу (1)некоторый сигнал для завершения.

Предпочтительно, чтобы отправитель и получатель были программами с открытым исходным кодом для Unix. Они могут общаться, используя сокет вместо труба, или любое другое творческое решение.

Однако, это важное ограничение, что каждый файл передается в момент, когда я повторяю его: недопустимо собирать список файлов, а затем вызывать один экземпляр scp, чтобы передать все файлы сразу в конце. Кроме того, у меня есть только простой доступ оболочки к принимающему хосту.

Update: я нашел решение проблемы накладных расходов на подключение, используя мультиплексирующие функции ssh, см. Мой собственный ответ ниже. Тем не менее, я начинаю щедрость, потому что мне любопытно узнать, существует ли программа отправителя/получателя, как я описываю здесь. Кажется, должно существовать что-то, что можно использовать, например xmodem/ymodem/zmodem?

14 10

14 ответов:

Этот способ будет работать, и для других вещей этот общий подход более или менее прав.

(
iterate over file list
  for each matching file
   echo filename
) | cpio -H newc -o | ssh remotehost cd location \&\& | cpio -H newc -imud

Я нашел решение с другой стороны. Начиная с версии 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

Если управляющий сокет больше не доступен (например, потому, что вы убили мастера), это возвращается к обычному соединению. Более подробная информация доступна в этой статье.

Можно использовать sftp вместо scp и перевести его в пакетный режим. Сделайте командный файл пакета каналом или доменным сокетом UNIX и подавайте в него команды по мере их выполнения.

Безопасность в этом случае может быть немного сложнее на клиентском конце.

Вы пробовали sshfs? Вы могли бы:

sshfs remote_user@remote_host:/remote_dir /mnt/local_dir

Где

  • /remote_dir был каталог, в который вы хотите отправить файлы в системе, в которую вы входите
  • /mnt/local_dir было локальное расположение горы

С помощью этой настройки вы можете просто cp файл в local_dir , и он будет отправлен по sftp в remote_host в его remote_dir

Обратите внимание, что существует одно соединение, поэтому существует мало на пути накладных расходов

Возможно, вам потребуется использовать флаг -o ServerAliveInterval=15 для поддержания неопределенного соединения

Вам нужно будет иметь fuse установлен локально и сервер SSH, поддерживающий (и настроенный для) sftp

Может быть, вы ищете это: ZSSH

Zssh (Zmodem SSH) - это программа для интерактивной передачи файлов на удаленную машину при использовании secure shell (ssh). Он призван стать удобной альтернативой scp, позволяющей передавать файлы без необходимости открывать еще один сеанс и повторно аутентифицировать себя.

Используйте rsync по ssh, если вы можете собрать все файлы для отправки в одном каталоге (или иерархии каталогов).

Если у вас нет всех файлов в одном месте, пожалуйста, дайте дополнительную информацию о том, чего вы хотите достичь и почему вы не можете упаковать все файлы в архив и отправить его. Почему так важно, чтобы каждый файл отправлялся немедленно? Было бы нормально, если бы файл был отправлен с небольшой задержкой (например, когда накопилось 4K данных)?

Это хорошая маленькая проблема. Я не знаю о готовом решении, но вы могли бы многое сделать с простыми сценариями оболочки. Я бы попробовал это в приемнике:

#!/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"

В конце концов вы захотите расширить сценарий, чтобы вы можете пройти через команды chmod и chgrp. Поскольку Вы доверяете отправляющему коду, вероятно, проще всего структурировать его так, чтобы получатель просто вызывал shell eval на каждой строке, а затем отправлял такие вещи, как

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

И затем определить локальную функцию read_and_copy_bytes. Правильное цитирование-это медведь, но в остальном оно должно быть простым.

Конечно, ничего из этого не было проверено! Но я надеюсь, что это даст вам несколько полезных идей.

Похоже на работу для тара? Передайте его выходные данные в ssh, а с другой стороны передайте выходные данные ssh обратно в tar.

Я думаю, что рабочий стол GNOME использует одно SSH-соединение при доступе к общему ресурсу через SFTP (SSH). Я предполагаю, что это то, что происходит, потому что я вижу один процесс SSH, когда я получаю доступ к удаленному общему ресурсу таким образом. Так что, если это правда, вы должны быть в состоянии использовать ту же программу для этой цели.

Новая версия GNOME использовала GVFS через GIO для выполнения всех видов ввода-вывода через различные бэкэнды. Пакет Ubuntu gvfs-bin предоставляет различные командные строки утилиты, которые позволяют управлять бэкэндами из командной строки.

Сначала вам нужно будет смонтировать папку SSH:

GVFS-mount sftp://user@host/

А затем вы можете использовать gvfs-copy для копирования ваших файлов. Я думаю, что все передачи файлов будут выполняться через один SSH-процесс. Вы даже можете использовать ps, чтобы увидеть, какой процесс используется.

Если вы чувствуете себя более предприимчивым, вы можете даже написать свою собственную программу на C или на каком-либо другом языке высокого уровня, который предоставляет API для GIO.

Одним из вариантов является Conch - это реализация SSH-клиента и сервера, написанная на Python с использованием платформы Twsited . Вы можете использовать его для написания инструмента, который принимает запросы через какой-то другой протокол (HTTP или Unix доменные сокеты, FTP, SSH или что-то еще) и запускает передачу файлов по длительному SSH-соединению. На самом деле, у меня есть несколько программ в производстве, которые используют эту технику, чтобы избежать нескольких установок SSH-соединения.

Былочень похожий вопрос здесь пару недель назад. В принятом ответе предлагалось открыть туннель при передаче ssh на удаленную машину и использовать этот туннель для передачи scp.

Perhapse CurlFTPFS может быть правильным решением для вас.

Похоже, что он просто монтирует папку внешнего компьютера на ваш компьютер через SFTP. Как только это будет сделано, вы сможете использовать свои обычные команды cp, и все будет сделано надежно.

К сожалению, я не смог проверить это сам, но дайте мне знать, если это работает для вас!

Edit 1: я смог загрузить и протестировать его. Как я и опасался, это действительно требует, чтобы клиент есть FTP-сервер. Однако я нашел другую программу, которая имеет точно такую же концепцию, как и то, что вы ищете. sshfs позволяет подключаться к клиентскому компьютеру без необходимости использования специального сервера. После того, как вы смонтировали одну из их папок, вы можете использовать свои обычные команды cp для перемещения любых файлов, которые вам нужны. Как только вы закончите, это должно быть вопросом улыбки umount /path/to/mounted/folder. Дайте мне знать, как это работает!

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

Это будет использовать SSH для передачи файлов, не медленным способом

Будьте проще, напишите небольшой скрипт-обертку, который делает что-то вроде этого.

  1. tar файлы
  2. отправить tar-файл
  3. унтар на другой стороне

Примерно так:

  1. tar-cvzf тест.файлы tgz ....
  2. Тест УПП.tgz user@other.site.com:.
  3. ssh user@other.site.com тест tar-xzvf.tgz

/ Йохан